summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/block/Kconfig7
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/sunvdc.c970
3 files changed, 978 insertions, 0 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 6e23af1ecbd..d9867fd2f2a 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -423,6 +423,13 @@ config ATA_OVER_ETH
This driver provides Support for ATA over Ethernet block
devices like the Coraid EtherDrive (R) Storage Blade.
+config SUNVDC
+ tristate "Sun Virtual Disk Client support"
+ depends on SUN_LDOMS
+ help
+ Support for virtual disk devices as a client under Sun
+ Logical Domains.
+
source "drivers/s390/block/Kconfig"
endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index e5f98acc5d5..43371c59623 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o
obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
+obj-$(CONFIG_SUNVDC) += sunvdc.o
obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
new file mode 100644
index 00000000000..8dbbeace52a
--- /dev/null
+++ b/drivers/block/sunvdc.c
@@ -0,0 +1,970 @@
+/* sunvdc.c: Sun LDOM Virtual Disk Client.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include <asm/vio.h>
+#include <asm/ldc.h>
+
+#define DRV_MODULE_NAME "sunvdc"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.0"
+#define DRV_MODULE_RELDATE "June 25, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun LDOM virtual disk client driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+#define VDC_TX_RING_SIZE 256
+
+#define WAITING_FOR_LINK_UP 0x01
+#define WAITING_FOR_TX_SPACE 0x02
+#define WAITING_FOR_GEN_CMD 0x04
+#define WAITING_FOR_ANY -1
+
+struct vdc_req_entry {
+ struct request *req;
+};
+
+struct vdc_port {
+ struct vio_driver_state vio;
+
+ struct vdc *vp;
+
+ struct gendisk *disk;
+
+ struct vdc_completion *cmp;
+
+ u64 req_id;
+ u64 seq;
+ struct vdc_req_entry rq_arr[VDC_TX_RING_SIZE];
+
+ unsigned long ring_cookies;
+
+ u64 max_xfer_size;
+ u32 vdisk_block_size;
+
+ /* The server fills these in for us in the disk attribute
+ * ACK packet.
+ */
+ u64 operations;
+ u32 vdisk_size;
+ u8 vdisk_type;
+ u8 dev_no;
+
+ char disk_name[32];
+
+ struct vio_disk_geom geom;
+ struct vio_disk_vtoc label;
+
+ struct list_head list;
+};
+
+static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
+{
+ return container_of(vio, struct vdc_port, vio);
+}
+
+struct vdc {
+ /* Protects prot_list. */
+ spinlock_t lock;
+
+ struct vio_dev *dev;
+
+ struct list_head port_list;
+};
+
+/* Ordered from largest major to lowest */
+static struct vio_version vdc_versions[] = {
+ { .major = 1, .minor = 0 },
+};
+
+#define VDCBLK_NAME "vdisk"
+static int vdc_major;
+#define PARTITION_SHIFT 3
+
+static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr)
+{
+ return vio_dring_avail(dr, VDC_TX_RING_SIZE);
+}
+
+static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct gendisk *disk = bdev->bd_disk;
+ struct vdc_port *port = disk->private_data;
+
+ geo->heads = (u8) port->geom.num_hd;
+ geo->sectors = (u8) port->geom.num_sec;
+ geo->cylinders = port->geom.num_cyl;
+
+ return 0;
+}
+
+static struct block_device_operations vdc_fops = {
+ .owner = THIS_MODULE,
+ .getgeo = vdc_getgeo,
+};
+
+static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
+{
+ if (vio->cmp &&
+ (waiting_for == -1 ||
+ vio->cmp->waiting_for == waiting_for)) {
+ vio->cmp->err = err;
+ complete(&vio->cmp->com);
+ vio->cmp = NULL;
+ }
+}
+
+static void vdc_handshake_complete(struct vio_driver_state *vio)
+{
+ vdc_finish(vio, 0, WAITING_FOR_LINK_UP);
+}
+
+static int vdc_handle_unknown(struct vdc_port *port, void *arg)
+{
+ struct vio_msg_tag *pkt = arg;
+
+ printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
+ pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
+ printk(KERN_ERR PFX "Resetting connection.\n");
+
+ ldc_disconnect(port->vio.lp);
+
+ return -ECONNRESET;
+}
+
+static int vdc_send_attr(struct vio_driver_state *vio)
+{
+ struct vdc_port *port = to_vdc_port(vio);
+ struct vio_disk_attr_info pkt;
+
+ memset(&pkt, 0, sizeof(pkt));
+
+ pkt.tag.type = VIO_TYPE_CTRL;
+ pkt.tag.stype = VIO_SUBTYPE_INFO;
+ pkt.tag.stype_env = VIO_ATTR_INFO;
+ pkt.tag.sid = vio_send_sid(vio);
+
+ pkt.xfer_mode = VIO_DRING_MODE;
+ pkt.vdisk_block_size = port->vdisk_block_size;
+ pkt.max_xfer_size = port->max_xfer_size;
+
+ viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
+ pkt.xfer_mode, pkt.vdisk_block_size, pkt.max_xfer_size);
+
+ return vio_ldc_send(&port->vio, &pkt, sizeof(pkt));
+}
+
+static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
+{
+ struct vdc_port *port = to_vdc_port(vio);
+ struct vio_disk_attr_info *pkt = arg;
+
+ viodbg(HS, "GOT ATTR stype[0x%x] ops[%lx] disk_size[%lu] disk_type[%x] "
+ "xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
+ pkt->tag.stype, pkt->operations,
+ pkt->vdisk_size, pkt->vdisk_type,
+ pkt->xfer_mode, pkt->vdisk_block_size,
+ pkt->max_xfer_size);
+
+ if (pkt->tag.stype == VIO_SUBTYPE_ACK) {
+ switch (pkt->vdisk_type) {
+ case VD_DISK_TYPE_DISK:
+ case VD_DISK_TYPE_SLICE:
+ break;
+
+ default:
+ printk(KERN_ERR PFX "%s: Bogus vdisk_type 0x%x\n",
+ vio->name, pkt->vdisk_type);
+ return -ECONNRESET;
+ }
+
+ if (pkt->vdisk_block_size > port->vdisk_block_size) {
+ printk(KERN_ERR PFX "%s: BLOCK size increased "
+ "%u --> %u\n",
+ vio->name,
+ port->vdisk_block_size, pkt->vdisk_block_size);
+ return -ECONNRESET;
+ }
+
+ port->operations = pkt->operations;
+ port->vdisk_size = pkt->vdisk_size;
+ port->vdisk_type = pkt->vdisk_type;
+ if (pkt->max_xfer_size < port->max_xfer_size)
+ port->max_xfer_size = pkt->max_xfer_size;
+ port->vdisk_block_size = pkt->vdisk_block_size;
+ return 0;
+ } else {
+ printk(KERN_ERR PFX "%s: Attribute NACK\n", vio->name);
+
+ return -ECONNRESET;
+ }
+}
+
+static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
+{
+ int err = desc->status;
+
+ vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
+}
+
+static void vdc_end_request(struct request *req, int uptodate, int num_sectors)
+{
+ if (end_that_request_first(req, uptodate, num_sectors))
+ return;
+ add_disk_randomness(req->rq_disk);
+ end_that_request_last(req, uptodate);
+}
+
+static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
+ unsigned int index)
+{
+ struct vio_disk_desc *desc = vio_dring_entry(dr, index);
+ struct vdc_req_entry *rqe = &port->rq_arr[index];
+ struct request *req;
+
+ if (unlikely(desc->hdr.state != VIO_DESC_DONE))
+ return;
+
+ ldc_unmap(port->vio.lp, desc->cookies, desc->ncookies);
+ desc->hdr.state = VIO_DESC_FREE;
+ dr->cons = (index + 1) & (VDC_TX_RING_SIZE - 1);
+
+ req = rqe->req;
+ if (req == NULL) {
+ vdc_end_special(port, desc);
+ return;
+ }
+
+ rqe->req = NULL;
+
+ vdc_end_request(req, !desc->status, desc->size >> 9);
+
+ if (blk_queue_stopped(port->disk->queue))
+ blk_start_queue(port->disk->queue);
+}
+
+static int vdc_ack(struct vdc_port *port, void *msgbuf)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct vio_dring_data *pkt = msgbuf;
+
+ if (unlikely(pkt->dring_ident != dr->ident ||
+ pkt->start_idx != pkt->end_idx ||
+ pkt->start_idx >= VDC_TX_RING_SIZE))
+ return 0;
+
+ vdc_end_one(port, dr, pkt->start_idx);
+
+ return 0;
+}
+
+static int vdc_nack(struct vdc_port *port, void *msgbuf)
+{
+ /* XXX Implement me XXX */
+ return 0;
+}
+
+static void vdc_event(void *arg, int event)
+{
+ struct vdc_port *port = arg;
+ struct vio_driver_state *vio = &port->vio;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&vio->lock, flags);
+
+ if (unlikely(event == LDC_EVENT_RESET ||
+ event == LDC_EVENT_UP)) {
+ vio_link_state_change(vio, event);
+ spin_unlock_irqrestore(&vio->lock, flags);
+ return;
+ }
+
+ if (unlikely(event != LDC_EVENT_DATA_READY)) {
+ printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+ spin_unlock_irqrestore(&vio->lock, flags);
+ return;
+ }
+
+ err = 0;
+ while (1) {
+ union {
+ struct vio_msg_tag tag;
+ u64 raw[8];
+ } msgbuf;
+
+ err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ vio_conn_reset(vio);
+ break;
+ }
+ if (err == 0)
+ break;
+ viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n",
+ msgbuf.tag.type,
+ msgbuf.tag.stype,
+ msgbuf.tag.stype_env,
+ msgbuf.tag.sid);
+ err = vio_validate_sid(vio, &msgbuf.tag);
+ if (err < 0)
+ break;
+
+ if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
+ if (msgbuf.tag.stype == VIO_SUBTYPE_ACK)
+ err = vdc_ack(port, &msgbuf);
+ else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK)
+ err = vdc_nack(port, &msgbuf);
+ else
+ err = vdc_handle_unknown(port, &msgbuf);
+ } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
+ err = vio_control_pkt_engine(vio, &msgbuf);
+ } else {
+ err = vdc_handle_unknown(port, &msgbuf);
+ }
+ if (err < 0)
+ break;
+ }
+ if (err < 0)
+ vdc_finish(&port->vio, err, WAITING_FOR_ANY);
+ spin_unlock_irqrestore(&vio->lock, flags);
+}
+
+static int __vdc_tx_trigger(struct vdc_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct vio_dring_data hdr = {
+ .tag = {
+ .type = VIO_TYPE_DATA,
+ .stype = VIO_SUBTYPE_INFO,
+ .stype_env = VIO_DRING_DATA,
+ .sid = vio_send_sid(&port->vio),
+ },
+ .dring_ident = dr->ident,
+ .start_idx = dr->prod,
+ .end_idx = dr->prod,
+ };
+ int err, delay;
+
+ hdr.seq = dr->snd_nxt;
+ delay = 1;
+ do {
+ err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
+ if (err > 0) {
+ dr->snd_nxt++;
+ break;
+ }
+ udelay(delay);
+ if ((delay <<= 1) > 128)
+ delay = 128;
+ } while (err == -EAGAIN);
+
+ return err;
+}
+
+static int __send_request(struct request *req)
+{
+ struct vdc_port *port = req->rq_disk->private_data;
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct scatterlist sg[port->ring_cookies];
+ struct vdc_req_entry *rqe;
+ struct vio_disk_desc *desc;
+ unsigned int map_perm;
+ int nsg, err, i;
+ u64 len;
+ u8 op;
+
+ map_perm = LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
+
+ if (rq_data_dir(req) == READ) {
+ map_perm |= LDC_MAP_W;
+ op = VD_OP_BREAD;
+ } else {
+ map_perm |= LDC_MAP_R;
+ op = VD_OP_BWRITE;
+ }
+
+ nsg = blk_rq_map_sg(req->q, req, sg);
+
+ len = 0;
+ for (i = 0; i < nsg; i++)
+ len += sg[i].length;
+
+ if (unlikely(vdc_tx_dring_avail(dr) < 1)) {
+ blk_stop_queue(port->disk->queue);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ desc = vio_dring_cur(dr);
+
+ err = ldc_map_sg(port->vio.lp, sg, nsg,
+ desc->cookies, port->ring_cookies,
+ map_perm);
+ if (err < 0) {
+ printk(KERN_ERR PFX "ldc_map_sg() failure, err=%d.\n", err);
+ return err;
+ }
+
+ rqe = &port->rq_arr[dr->prod];
+ rqe->req = req;
+
+ desc->hdr.ack = VIO_ACK_ENABLE;
+ desc->req_id = port->req_id;
+ desc->operation = op;
+ if (port->vdisk_type == VD_DISK_TYPE_DISK) {
+ desc->slice = 2;
+ } else {
+ desc->slice = 0;
+ }
+ desc->status = ~0;
+ desc->offset = (req->sector << 9) / port->vdisk_block_size;
+ desc->size = len;
+ desc->ncookies = err;
+
+ /* This has to be a non-SMP write barrier because we are writing
+ * to memory which is shared with the peer LDOM.
+ */
+ wmb();
+ desc->hdr.state = VIO_DESC_READY;
+
+ err = __vdc_tx_trigger(port);
+ if (err < 0) {
+ printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err);
+ } else {
+ port->req_id++;
+ dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
+ }
+out:
+
+ return err;
+}
+
+static void do_vdc_request(request_queue_t *q)
+{
+ while (1) {
+ struct request *req = elv_next_request(q);
+
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+ if (__send_request(req) < 0)
+ vdc_end_request(req, 0, req->hard_nr_sectors);
+ }
+}
+
+static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
+{
+ struct vio_dring_state *dr;
+ struct vio_completion comp;
+ struct vio_disk_desc *desc;
+ unsigned int map_perm;
+ unsigned long flags;
+ int op_len, err;
+ void *req_buf;
+
+ if (!(((u64)1 << ((u64)op - 1)) & port->operations))
+ return -EOPNOTSUPP;
+
+ switch (op) {
+ case VD_OP_BREAD:
+ case VD_OP_BWRITE:
+ default:
+ return -EINVAL;
+
+ case VD_OP_FLUSH:
+ op_len = 0;
+ map_perm = 0;
+ break;
+
+ case VD_OP_GET_WCE:
+ op_len = sizeof(u32);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_SET_WCE:
+ op_len = sizeof(u32);
+ map_perm = LDC_MAP_R;
+ break;
+
+ case VD_OP_GET_VTOC:
+ op_len = sizeof(struct vio_disk_vtoc);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_SET_VTOC:
+ op_len = sizeof(struct vio_disk_vtoc);
+ map_perm = LDC_MAP_R;
+ break;
+
+ case VD_OP_GET_DISKGEOM:
+ op_len = sizeof(struct vio_disk_geom);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_SET_DISKGEOM:
+ op_len = sizeof(struct vio_disk_geom);
+ map_perm = LDC_MAP_R;
+ break;
+
+ case VD_OP_SCSICMD:
+ op_len = 16;
+ map_perm = LDC_MAP_RW;
+ break;
+
+ case VD_OP_GET_DEVID:
+ op_len = sizeof(struct vio_disk_devid);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_GET_EFI:
+ case VD_OP_SET_EFI:
+ return -EOPNOTSUPP;
+ break;
+ };
+
+ map_perm |= LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
+
+ op_len = (op_len + 7) & ~7;
+ req_buf = kzalloc(op_len, GFP_KERNEL);
+ if (!req_buf)
+ return -ENOMEM;
+
+ if (len > op_len)
+ len = op_len;
+
+ if (map_perm & LDC_MAP_R)
+ memcpy(req_buf, buf, len);
+
+ spin_lock_irqsave(&port->vio.lock, flags);
+
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+
+ /* XXX If we want to use this code generically we have to
+ * XXX handle TX ring exhaustion etc.
+ */
+ desc = vio_dring_cur(dr);
+
+ err = ldc_map_single(port->vio.lp, req_buf, op_len,
+ desc->cookies, port->ring_cookies,
+ map_perm);
+ if (err < 0) {
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+ kfree(req_buf);
+ return err;
+ }
+
+ init_completion(&comp.com);
+ comp.waiting_for = WAITING_FOR_GEN_CMD;
+ port->vio.cmp = &comp;
+
+ desc->hdr.ack = VIO_ACK_ENABLE;
+ desc->req_id = port->req_id;
+ desc->operation = op;
+ desc->slice = 0;
+ desc->status = ~0;
+ desc->offset = 0;
+ desc->size = op_len;
+ desc->ncookies = err;
+
+ /* This has to be a non-SMP write barrier because we are writing
+ * to memory which is shared with the peer LDOM.
+ */
+ wmb();
+ desc->hdr.state = VIO_DESC_READY;
+
+ err = __vdc_tx_trigger(port);
+ if (err >= 0) {
+ port->req_id++;
+ dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+
+ wait_for_completion(&comp.com);
+ err = comp.err;
+ } else {
+ port->vio.cmp = NULL;
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+ }
+
+ if (map_perm & LDC_MAP_W)
+ memcpy(buf, req_buf, len);
+
+ kfree(req_buf);
+
+ return err;
+}
+
+static int __devinit vdc_alloc_tx_ring(struct vdc_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ unsigned long len, entry_size;
+ int ncookies;
+ void *dring;
+
+ entry_size = sizeof(struct vio_disk_desc) +
+ (sizeof(struct ldc_trans_cookie) * port->ring_cookies);
+ len = (VDC_TX_RING_SIZE * entry_size);
+
+ ncookies = VIO_MAX_RING_COOKIES;
+ dring = ldc_alloc_exp_dring(port->vio.lp, len,
+ dr->cookies, &ncookies,
+ (LDC_MAP_SHADOW |
+ LDC_MAP_DIRECT |
+ LDC_MAP_RW));
+ if (IS_ERR(dring))
+ return PTR_ERR(dring);
+
+ dr->base = dring;
+ dr->entry_size = entry_size;
+ dr->num_entries = VDC_TX_RING_SIZE;
+ dr->prod = dr->cons = 0;
+ dr->pending = VDC_TX_RING_SIZE;
+ dr->ncookies = ncookies;
+
+ return 0;
+}
+
+static void vdc_free_tx_ring(struct vdc_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+
+ if (dr->base) {
+ ldc_free_exp_dring(port->vio.lp, dr->base,
+ (dr->entry_size * dr->num_entries),
+ dr->cookies, dr->ncookies);
+ dr->base = NULL;
+ dr->entry_size = 0;
+ dr->num_entries = 0;
+ dr->pending = 0;
+ dr->ncookies = 0;
+ }
+}
+
+static int probe_disk(struct vdc_port *port)
+{
+ struct vio_completion comp;
+ struct request_queue *q;
+ struct gendisk *g;
+ int err;
+
+ init_completion(&comp.com);
+ comp.err = 0;
+ comp.waiting_for = WAITING_FOR_LINK_UP;
+ port->vio.cmp = &comp;
+
+ vio_port_up(&port->vio);
+
+ wait_for_completion(&comp.com);
+ if (comp.err)
+ return comp.err;
+
+ err = generic_request(port, VD_OP_GET_VTOC,
+ &port->label, sizeof(port->label));
+ if (err < 0) {
+ printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err);
+ return err;
+ }
+
+ err = generic_request(port, VD_OP_GET_DISKGEOM,
+ &port->geom, sizeof(port->geom));
+ if (err < 0) {
+ printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
+ "error %d\n", err);
+ return err;
+ }
+
+ port->vdisk_size = ((u64)port->geom.num_cyl *
+ (u64)port->geom.num_hd *
+ (u64)port->geom.num_sec);
+
+ q = blk_init_queue(do_vdc_request, &port->vio.lock);
+ if (!q) {
+ printk(KERN_ERR PFX "%s: Could not allocate queue.\n",
+ port->vio.name);
+ return -ENOMEM;
+ }
+ g = alloc_disk(1 << PARTITION_SHIFT);
+ if (!g) {
+ printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n",
+ port->vio.name);
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ port->disk = g;
+
+ blk_queue_max_hw_segments(q, port->ring_cookies);
+ blk_queue_max_phys_segments(q, port->ring_cookies);
+ blk_queue_max_sectors(q, port->max_xfer_size);
+ g->major = vdc_major;
+ g->first_minor = port->dev_no << PARTITION_SHIFT;
+ strcpy(g->disk_name, port->disk_name);
+
+ g->fops = &vdc_fops;
+ g->queue = q;
+ g->private_data = port;
+ g->driverfs_dev = &port->vio.vdev->dev;
+
+ set_capacity(g, port->vdisk_size);
+
+ printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n",
+ g->disk_name,
+ port->vdisk_size, (port->vdisk_size >> (20 - 9)));
+
+ add_disk(g);
+
+ return 0;
+}
+
+static struct ldc_channel_config vdc_ldc_cfg = {
+ .event = vdc_event,
+ .mtu = 64,
+ .mode = LDC_MODE_UNRELIABLE,
+};
+
+static struct vio_driver_ops vdc_vio_ops = {
+ .send_attr = vdc_send_attr,
+ .handle_attr = vdc_handle_attr,
+ .handshake_complete = vdc_handshake_complete,
+};
+
+static int __devinit vdc_port_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ struct mdesc_node *endp;
+ struct vdc_port *port;
+ unsigned long flags;
+ struct vdc *vp;
+ const u64 *port_id;
+ int err;
+
+ vp = dev_get_drvdata(vdev->dev.parent);
+ if (!vp) {
+ printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
+ return -ENODEV;
+ }
+
+ endp = vio_find_endpoint(vdev);
+ if (!endp) {
+ printk(KERN_ERR PFX "Port lacks channel-endpoint.\n");
+ return -ENODEV;
+ }
+
+ port_id = md_get_property(vdev->mp, "id", NULL);
+ if (!port_id) {
+ printk(KERN_ERR PFX "Port lacks id property.\n");
+ return -ENODEV;
+ }
+ if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+ printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+ return -ENODEV;
+ }
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port) {
+ printk(KERN_ERR PFX "Cannot allocate vdc_port.\n");
+ return -ENOMEM;
+ }
+
+ port->vp = vp;
+ port->dev_no = *port_id;
+
+ if (port->dev_no >= 26)
+ snprintf(port->disk_name, sizeof(port->disk_name),
+ VDCBLK_NAME "%c%c",
+ 'a' + (port->dev_no / 26) - 1,
+ 'a' + (port->dev_no % 26));
+ else
+ snprintf(port->disk_name, sizeof(port->disk_name),
+ VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+
+ err = vio_driver_init(&port->vio, vdev, VDEV_DISK, endp,
+ vdc_versions, ARRAY_SIZE(vdc_versions),
+ &vdc_vio_ops, port->disk_name);
+ if (err)
+ goto err_out_free_port;
+
+ port->vdisk_block_size = 512;
+ port->max_xfer_size = ((128 * 1024) / port->vdisk_block_size);
+ port->ring_cookies = ((port->max_xfer_size *
+ port->vdisk_block_size) / PAGE_SIZE) + 2;
+
+ err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port);
+ if (err)
+ goto err_out_free_port;
+
+ err = vdc_alloc_tx_ring(port);
+ if (err)
+ goto err_out_free_ldc;
+
+ err = probe_disk(port);
+ if (err)
+ goto err_out_free_tx_ring;
+
+ INIT_LIST_HEAD(&port->list);
+
+ spin_lock_irqsave(&vp->lock, flags);
+ list_add(&port->list, &vp->port_list);
+ spin_unlock_irqrestore(&vp->lock, flags);
+
+ dev_set_drvdata(&vdev->dev, port);
+
+ return 0;
+
+err_out_free_tx_ring:
+ vdc_free_tx_ring(port);
+
+err_out_free_ldc:
+ vio_ldc_free(&port->vio);
+
+err_out_free_port:
+ kfree(port);
+
+ return err;
+}
+
+static int vdc_port_remove(struct vio_dev *vdev)
+{
+ struct vdc_port *port = dev_get_drvdata(&vdev->dev);
+
+ if (port) {
+ del_timer_sync(&port->vio.timer);
+
+ vdc_free_tx_ring(port);
+ vio_ldc_free(&port->vio);
+
+ dev_set_drvdata(&vdev->dev, NULL);
+
+ kfree(port);
+ }
+ return 0;
+}
+
+static struct vio_device_id vdc_port_match[] = {
+ {
+ .type = "vdc-port",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(vio, vdc_match);
+
+static struct vio_driver vdc_port_driver = {
+ .id_table = vdc_port_match,
+ .probe = vdc_port_probe,
+ .remove = vdc_port_remove,
+ .driver = {
+ .name = "vdc_port",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __devinit vdc_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ static int vdc_version_printed;
+ struct vdc *vp;
+
+ if (vdc_version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
+ if (!vp)
+ return -ENOMEM;
+
+ spin_lock_init(&vp->lock);
+ vp->dev = vdev;
+ INIT_LIST_HEAD(&vp->port_list);
+
+ dev_set_drvdata(&vdev->dev, vp);
+
+ return 0;
+}
+
+static int vdc_remove(struct vio_dev *vdev)
+{
+
+ struct vdc *vp = dev_get_drvdata(&vdev->dev);
+
+ if (vp) {
+ kfree(vp);
+ dev_set_drvdata(&vdev->dev, NULL);
+ }
+ return 0;
+}
+
+static struct vio_device_id vdc_match[] = {
+ {
+ .type = "block",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(vio, vdc_match);
+
+static struct vio_driver vdc_driver = {
+ .id_table = vdc_match,
+ .probe = vdc_probe,
+ .remove = vdc_remove,
+ .driver = {
+ .name = "vdc",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init vdc_init(void)
+{
+ int err;
+
+ err = register_blkdev(0, VDCBLK_NAME);
+ if (err < 0)
+ goto out_err;
+
+ vdc_major = err;
+ err = vio_register_driver(&vdc_driver);
+ if (err)
+ goto out_unregister_blkdev;
+
+ err = vio_register_driver(&vdc_port_driver);
+ if (err)
+ goto out_unregister_vdc;
+
+ return 0;
+
+out_unregister_vdc:
+ vio_unregister_driver(&vdc_driver);
+
+out_unregister_blkdev:
+ unregister_blkdev(vdc_major, VDCBLK_NAME);
+ vdc_major = 0;
+
+out_err:
+ return err;
+}
+
+static void __exit vdc_exit(void)
+{
+ vio_unregister_driver(&vdc_port_driver);
+ vio_unregister_driver(&vdc_driver);
+ unregister_blkdev(vdc_major, VDCBLK_NAME);
+}
+
+module_init(vdc_init);
+module_exit(vdc_exit);
file diffstat' width='100%'> -rw-r--r--fs/gfs2/ops_fstype.c3
-rw-r--r--fs/gfs2/super.c36
-rw-r--r--fs/gfs2/sys.c7
-rw-r--r--fs/hppfs/hppfs.c31
-rw-r--r--fs/libfs.c2
-rw-r--r--fs/namei.c9
-rw-r--r--fs/nfs/nfs4filelayout.c1
-rw-r--r--fs/nfs/nfs4xdr.c2
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/ufs/namei.c12
-rw-r--r--include/acpi/acpi_bus.h2
-rw-r--r--include/acpi/acpi_drivers.h2
-rw-r--r--include/acpi/acpiosxf.h3
-rw-r--r--include/acpi/acpixf.h3
-rw-r--r--include/acpi/platform/aclinux.h18
-rw-r--r--include/acpi/processor.h2
-rw-r--r--include/drm/drm_pciids.h2
-rw-r--r--include/linux/acpi.h1
-rw-r--r--include/linux/mmc/card.h13
-rw-r--r--include/linux/netdevice.h6
-rw-r--r--include/linux/sched.h17
-rw-r--r--include/linux/sdla.h6
-rw-r--r--include/linux/thermal.h22
-rw-r--r--include/net/sctp/command.h1
-rw-r--r--include/net/sctp/ulpevent.h2
-rw-r--r--kernel/rcutree.c26
-rw-r--r--kernel/rcutree_plugin.h68
-rw-r--r--kernel/sched.c236
-rw-r--r--kernel/sched_fair.c46
-rw-r--r--kernel/sched_features.h2
-rw-r--r--kernel/signal.c19
-rw-r--r--kernel/softirq.c12
-rw-r--r--mm/vmscan.c3
-rw-r--r--net/8021q/vlan_dev.c6
-rw-r--r--net/bluetooth/hci_conn.c3
-rw-r--r--net/bluetooth/hidp/core.c18
-rw-r--r--net/bluetooth/hidp/hidp.h1
-rw-r--r--net/bluetooth/l2cap_core.c10
-rw-r--r--net/ceph/ceph_fs.c17
-rw-r--r--net/mac80211/scan.c3
-rw-r--r--net/mac80211/wpa.c16
-rw-r--r--net/sctp/output.c19
-rw-r--r--net/sctp/outqueue.c20
-rw-r--r--net/sctp/sm_sideeffect.c20
-rw-r--r--net/sctp/sm_statefuns.c32
-rw-r--r--net/sctp/sm_statetable.c2
-rw-r--r--net/sctp/socket.c13
-rw-r--r--net/sctp/ulpevent.c16
-rw-r--r--net/sunrpc/rpcb_clnt.c2
-rw-r--r--net/sunrpc/sched.c27
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c24
-rw-r--r--net/wireless/scan.c10
-rw-r--r--net/xfrm/xfrm_state.c2
-rwxr-xr-xscripts/depmod.sh10
-rw-r--r--sound/soc/codecs/wm8994.c9
-rw-r--r--sound/soc/sh/fsi-ak4642.c16
-rw-r--r--sound/soc/sh/fsi-da7210.c2
-rw-r--r--sound/soc/sh/fsi-hdmi.c4
164 files changed, 1482 insertions, 725 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index b1c921c2751..951143dd068 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -310,15 +310,6 @@ Who: Ravikiran Thirumalai <kiran@scalex86.org>
---------------------------
-What: CONFIG_THERMAL_HWMON
-When: January 2009
-Why: This option was introduced just to allow older lm-sensors userspace
- to keep working over the upgrade to 2.6.26. At the scheduled time of
- removal fixed lm-sensors (2.x or 3.x) should be readily available.
-Who: Rene Herman <rene.herman@gmail.com>
-
----------------------------
-
What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS
(in net/core/net-sysfs.c)
When: After the only user (hal) has seen a release with the patches
diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt
index d5c0cef38a7..873a2ab2e9f 100644
--- a/Documentation/filesystems/nilfs2.txt
+++ b/Documentation/filesystems/nilfs2.txt
@@ -40,7 +40,6 @@ Features which NILFS2 does not support yet:
- POSIX ACLs
- quotas
- fsck
- - resize
- defragmentation
Mount options
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index aa47be71df4..37713bcf777 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -163,6 +163,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
See also Documentation/power/pm.txt, pci=noacpi
+ acpi_rsdp= [ACPI,EFI,KEXEC]
+ Pass the RSDP address to the kernel, mostly used
+ on machines running EFI runtime service to boot the
+ second kernel for kdump.
+
acpi_apic_instance= [ACPI, IOAPIC]
Format: <int>
2: use 2nd APIC table, if available
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index d3d653a5f9b..bfe924217f2 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -346,7 +346,7 @@ tcp_orphan_retries - INTEGER
when RTO retransmissions remain unacknowledged.
See tcp_retries2 for more details.
- The default value is 7.
+ The default value is 8.
If your machine is a loaded WEB server,
you should think about lowering this value, such sockets
may consume significant resources. Cf. tcp_max_orphans.
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index 9b7221a86df..7c3a8801b7c 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -674,7 +674,7 @@ Protocol: 2.10+
Field name: init_size
Type: read
-Offset/size: 0x25c/4
+Offset/size: 0x260/4
This field indicates the amount of linear contiguous memory starting
at the kernel runtime start address that the kernel needs before it
diff --git a/Makefile b/Makefile
index 60d91f76c2f..6a5bdad524a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 0
SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
NAME = Sneaky Weasel
# *DOCUMENTATION*
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index c67f684ee3e..09a87e61ffc 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -520,7 +520,7 @@ fail:
*/
if (have_imager()) {
label = "HD imager";
- mux |= 1;
+ mux |= 2;
/* externally mux MMC1/ENET/AIC33 to imager */
mux |= BIT(6) | BIT(5) | BIT(3);
@@ -540,7 +540,7 @@ fail:
resets &= ~BIT(1);
if (have_tvp7002()) {
- mux |= 2;
+ mux |= 1;
resets &= ~BIT(2);
label = "tvp7002 HD";
} else {
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index e7221398e5a..cafbe13a82a 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -254,8 +254,10 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
struct davinci_gpio_regs __iomem *g;
u32 mask = 0xffff;
+ struct davinci_gpio_controller *d;
- g = (__force struct davinci_gpio_regs __iomem *) irq_desc_get_handler_data(desc);
+ d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc);
+ g = (struct davinci_gpio_regs __iomem *)d->regs;
/* we only care about one bank */
if (irq & 1)
@@ -274,11 +276,14 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
if (!status)
break;
__raw_writel(status, &g->intstat);
- if (irq & 1)
- status >>= 16;
/* now demux them to the right lowlevel handler */
- n = (int)irq_get_handler_data(irq);
+ n = d->irq_base;
+ if (irq & 1) {
+ n += 16;
+ status >>= 16;
+ }
+
while (status) {
res = ffs(status);
n += res;
@@ -424,7 +429,13 @@ static int __init davinci_gpio_irq_setup(void)
/* set up all irqs in this bank */
irq_set_chained_handler(bank_irq, gpio_irq_handler);
- irq_set_handler_data(bank_irq, (__force void *)g);
+
+ /*
+ * Each chip handles 32 gpios, and each irq bank consists of 16
+ * gpio irqs. Pass the irq bank's corresponding controller to
+ * the chained irq handler.
+ */
+ irq_set_handler_data(bank_irq, &chips[gpio / 32]);
for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
irq_set_chip(irq, &gpio_irqchip);
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index d8c1af02593..952dc126c39 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -52,6 +52,12 @@ davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
struct irq_chip_type *ct;
gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq);
+ if (!gc) {
+ pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n",
+ __func__, irq_start);
+ return;
+ }
+
ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 74ed81a3cb1..07772575d7a 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -419,14 +419,20 @@ static void notrace ixp4xx_update_sched_clock(void)
/*
* clocksource
*/
+
+static cycle_t ixp4xx_clocksource_read(struct clocksource *c)
+{
+ return *IXP4XX_OSTS;
+}
+
unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
EXPORT_SYMBOL(ixp4xx_timer_freq);
static void __init ixp4xx_clocksource_init(void)
{
init_sched_clock(&cd, ixp4xx_update_sched_clock, 32, ixp4xx_timer_freq);
- clocksource_mmio_init(&IXP4XX_OSTS, "OSTS", ixp4xx_timer_freq, 200, 32,
- clocksource_mmio_readl_up);
+ clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32,
+ ixp4xx_clocksource_read);
}
/*
diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c
index b197171e7d0..204bfafe4bf 100644
--- a/arch/arm/mach-s3c64xx/dma.c
+++ b/arch/arm/mach-s3c64xx/dma.c
@@ -113,7 +113,7 @@ found:
return chan;
}
-int s3c2410_dma_config(unsigned int channel, int xferunit)
+int s3c2410_dma_config(enum dma_ch channel, int xferunit)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -297,7 +297,7 @@ static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan)
return 0;
}
-int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
+int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -331,7 +331,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl);
*
*/
-int s3c2410_dma_enqueue(unsigned int channel, void *id,
+int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
dma_addr_t data, int size)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -415,7 +415,7 @@ err_buff:
EXPORT_SYMBOL(s3c2410_dma_enqueue);
-int s3c2410_dma_devconfig(unsigned int channel,
+int s3c2410_dma_devconfig(enum dma_ch channel,
enum s3c2410_dmasrc source,
unsigned long devaddr)
{
@@ -463,7 +463,7 @@ int s3c2410_dma_devconfig(unsigned int channel,
EXPORT_SYMBOL(s3c2410_dma_devconfig);
-int s3c2410_dma_getposition(unsigned int channel,
+int s3c2410_dma_getposition(enum dma_ch channel,
dma_addr_t *src, dma_addr_t *dst)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -487,7 +487,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition);
* get control of an dma channel
*/
-int s3c2410_dma_request(unsigned int channel,
+int s3c2410_dma_request(enum dma_ch channel,
struct s3c2410_dma_client *client,
void *dev)
{
@@ -533,7 +533,7 @@ EXPORT_SYMBOL(s3c2410_dma_request);
* allowed to go through.
*/
-int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
+int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned long flags;
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index a79a8ccd25f..539bd0e3def 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -712,7 +712,7 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
* get control of an dma channel
*/
-int s3c2410_dma_request(unsigned int channel,
+int s3c2410_dma_request(enum dma_ch channel,
struct s3c2410_dma_client *client,
void *dev)
{
@@ -783,7 +783,7 @@ EXPORT_SYMBOL(s3c2410_dma_request);
* allowed to go through.
*/
-int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
+int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned long flags;
@@ -974,7 +974,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
}
int
-s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
+s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -1021,7 +1021,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl);
* xfersize: size of unit in bytes (1,2,4)
*/
-int s3c2410_dma_config(unsigned int channel,
+int s3c2410_dma_config(enum dma_ch channel,
int xferunit)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -1100,7 +1100,7 @@ EXPORT_SYMBOL(s3c2410_dma_config);
* devaddr: physical address of the source
*/
-int s3c2410_dma_devconfig(unsigned int channel,
+int s3c2410_dma_devconfig(enum dma_ch channel,
enum s3c2410_dmasrc source,
unsigned long devaddr)
{
@@ -1173,7 +1173,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
* returns the current transfer points for the dma source and destination
*/
-int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst)
+int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
diff --git a/arch/arm/plat-samsung/dma.c b/arch/arm/plat-samsung/dma.c
index cb459dd9545..6143aa14768 100644
--- a/arch/arm/plat-samsung/dma.c
+++ b/arch/arm/plat-samsung/dma.c
@@ -41,7 +41,7 @@ struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel)
* irq?
*/
-int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
+int s3c2410_dma_set_opfn(enum dma_ch channel, s3c2410_dma_opfn_t rtn)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -56,7 +56,7 @@ int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
}
EXPORT_SYMBOL(s3c2410_dma_set_opfn);
-int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
+int s3c2410_dma_set_buffdone_fn(enum dma_ch channel, s3c2410_dma_cbfn_t rtn)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -71,7 +71,7 @@ int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
}
EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
-int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
+int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h
index 2e8f8c6560d..8c273b7a6f5 100644
--- a/arch/arm/plat-samsung/include/plat/dma.h
+++ b/arch/arm/plat-samsung/include/plat/dma.h
@@ -42,6 +42,7 @@ struct s3c2410_dma_client {
};
struct s3c2410_dma_chan;
+enum dma_ch;
/* s3c2410_dma_cbfn_t
*
@@ -62,7 +63,7 @@ typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
* request a dma channel exclusivley
*/
-extern int s3c2410_dma_request(unsigned int channel,
+extern int s3c2410_dma_request(enum dma_ch channel,
struct s3c2410_dma_client *, void *dev);
@@ -71,14 +72,14 @@ extern int s3c2410_dma_request(unsigned int channel,
* change the state of the dma channel
*/
-extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
+extern int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op);
/* s3c2410_dma_setflags
*
* set the channel's flags to a given state
*/
-extern int s3c2410_dma_setflags(unsigned int channel,
+extern int s3c2410_dma_setflags(enum dma_ch channel,
unsigned int flags);
/* s3c2410_dma_free
@@ -86,7 +87,7 @@ extern int s3c2410_dma_setflags(unsigned int channel,
* free the dma channel (will also abort any outstanding operations)
*/
-extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
+extern int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *);
/* s3c2410_dma_enqueue
*
@@ -95,7 +96,7 @@ extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
* drained before the buffer is given to the DMA system.
*/
-extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
+extern int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
dma_addr_t data, int size);
/* s3c2410_dma_config
@@ -103,14 +104,14 @@ extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
* configure the dma channel
*/
-extern int s3c2410_dma_config(unsigned int channel, int xferunit);
+extern int s3c2410_dma_config(enum dma_ch channel, int xferunit);
/* s3c2410_dma_devconfig
*
* configure the device we're talking to
*/
-extern int s3c2410_dma_devconfig(unsigned int channel,
+extern int s3c2410_dma_devconfig(enum dma_ch channel,
enum s3c2410_dmasrc source, unsigned long devaddr);
/* s3c2410_dma_getposition
@@ -118,10 +119,10 @@ extern int s3c2410_dma_devconfig(unsigned int channel,
* get the position that the dma transfer is currently at
*/
-extern int s3c2410_dma_getposition(unsigned int channel,
+extern int s3c2410_dma_getposition(enum dma_ch channel,
dma_addr_t *src, dma_addr_t *dest);
-extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
-extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
+extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn);
+extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn);
diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c
index 0e46588d847..657405c481d 100644
--- a/arch/arm/plat-samsung/irq-uart.c
+++ b/arch/arm/plat-samsung/irq-uart.c
@@ -54,6 +54,13 @@ static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base,
handle_level_irq);
+
+ if (!gc) {
+ pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n",
+ __func__, uirq->base_irq);
+ return;
+ }
+
ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_set_bit;
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
index a607546ddbd..f714d060370 100644
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -54,6 +54,13 @@ void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq)
s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq,
S3C64XX_TINT_CSTAT, handle_level_irq);
+
+ if (!s3c_tgc) {
+ pr_err("%s: irq_alloc_generic_chip for IRQ %d failed\n",
+ __func__, timer_irq);
+ return;
+ }
+
ct = s3c_tgc->chip_types;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index c018696765d..5c74eb797f0 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/irq.h>
#include <asm/i8259.h>
@@ -215,14 +215,13 @@ spurious_8259A_irq:
}
}
-static int i8259A_resume(struct sys_device *dev)
+static void i8259A_resume(void)
{
if (i8259A_auto_eoi >= 0)
init_8259A(i8259A_auto_eoi);
- return 0;
}
-static int i8259A_shutdown(struct sys_device *dev)
+static void i8259A_shutdown(void)
{
/* Put the i8259A into a quiescent state that
* the kernel initialization code can get it
@@ -232,26 +231,17 @@ static int i8259A_shutdown(struct sys_device *dev)
outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */
}
- return 0;
}
-static struct sysdev_class i8259_sysdev_class = {
- .name = "i8259",
+static struct syscore_ops i8259_syscore_ops = {
.resume = i8259A_resume,
.shutdown = i8259A_shutdown,
};
-static struct sys_device device_i8259A = {
- .id = 0,
- .cls = &i8259_sysdev_class,
-};
-
static int __init i8259A_init_sysfs(void)
{
- int error = sysdev_class_register(&i8259_sysdev_class);
- if (!error)
- error = sysdev_register(&device_i8259A);
- return error;
+ register_syscore_ops(&i8259_syscore_ops);
+ return 0;
}
device_initcall(i8259A_init_sysfs);
diff --git a/arch/sparc/include/asm/irqflags_32.h b/arch/sparc/include/asm/irqflags_32.h
index d4d0711de0f..14848909e0d 100644
--- a/arch/sparc/include/asm/irqflags_32.h
+++ b/arch/sparc/include/asm/irqflags_32.h
@@ -18,7 +18,7 @@ extern void arch_local_irq_restore(unsigned long);
extern unsigned long arch_local_irq_save(void);
extern void arch_local_irq_enable(void);
-static inline unsigned long arch_local_save_flags(void)
+static inline notrace unsigned long arch_local_save_flags(void)
{
unsigned long flags;
@@ -26,17 +26,17 @@ static inline unsigned long arch_local_save_flags(void)
return flags;
}
-static inline void arch_local_irq_disable(void)
+static inline notrace void arch_local_irq_disable(void)
{
arch_local_irq_save();
}
-static inline bool arch_irqs_disabled_flags(unsigned long flags)
+static inline notrace bool arch_irqs_disabled_flags(unsigned long flags)
{
return (flags & PSR_PIL) != 0;
}
-static inline bool arch_irqs_disabled(void)
+static inline notrace bool arch_irqs_disabled(void)
{
return arch_irqs_disabled_flags(arch_local_save_flags());
}
diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h
index aab969c82c2..23cd27f6beb 100644
--- a/arch/sparc/include/asm/irqflags_64.h
+++ b/arch/sparc/include/asm/irqflags_64.h
@@ -14,7 +14,7 @@
#ifndef __ASSEMBLY__
-static inline unsigned long arch_local_save_flags(void)
+static inline notrace unsigned long arch_local_save_flags(void)
{
unsigned long flags;
@@ -26,7 +26,7 @@ static inline unsigned long arch_local_save_flags(void)
return flags;
}
-static inline void arch_local_irq_restore(unsigned long flags)
+static inline notrace void arch_local_irq_restore(unsigned long flags)
{
__asm__ __volatile__(
"wrpr %0, %%pil"
@@ -36,7 +36,7 @@ static inline void arch_local_irq_restore(unsigned long flags)
);
}
-static inline void arch_local_irq_disable(void)
+static inline notrace void arch_local_irq_disable(void)
{
__asm__ __volatile__(
"wrpr %0, %%pil"
@@ -46,7 +46,7 @@ static inline void arch_local_irq_disable(void)
);
}
-static inline void arch_local_irq_enable(void)
+static inline notrace void arch_local_irq_enable(void)
{
__asm__ __volatile__(
"wrpr 0, %%pil"
@@ -56,17 +56,17 @@ static inline void arch_local_irq_enable(void)
);
}
-static inline int arch_irqs_disabled_flags(unsigned long flags)
+static inline notrace int arch_irqs_disabled_flags(unsigned long flags)
{
return (flags > 0);
}
-static inline int arch_irqs_disabled(void)
+static inline notrace int arch_irqs_disabled(void)
{
return arch_irqs_disabled_flags(arch_local_save_flags());
}
-static inline unsigned long arch_local_irq_save(void)
+static inline notrace unsigned long arch_local_irq_save(void)
{
unsigned long flags, tmp;
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index c7ad3fe2b25..b928b31424b 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -205,6 +205,7 @@ do { current_thread_info()->syscall_noerror = 1; \
} while (0)
#define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
#define instruction_pointer(regs) ((regs)->tpc)
+#define instruction_pointer_set(regs, val) ((regs)->tpc = (val))
#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
#define regs_return_value(regs) ((regs)->u_regs[UREG_I0])
#ifdef CONFIG_SMP
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 9fe08a1ea6c..f445e98463e 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -293,7 +293,7 @@ maybe_smp4m_msg:
WRITE_PAUSE
wr %l4, PSR_ET, %psr
WRITE_PAUSE
- sll %o3, 28, %o2 ! shift for simpler checks below
+ srl %o3, 28, %o2 ! shift for simpler checks below
maybe_smp4m_msg_check_single:
andcc %o2, 0x1, %g0
beq,a maybe_smp4m_msg_check_mask
diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c
index c0e01297e64..e485a680499 100644
--- a/arch/sparc/mm/leon_mm.c
+++ b/arch/sparc/mm/leon_mm.c
@@ -226,7 +226,7 @@ void leon3_getCacheRegs(struct leon3_cacheregs *regs)
* Leon2 and Leon3 differ in their way of telling cache information
*
*/
-int leon_flush_needed(void)
+int __init leon_flush_needed(void)
{
int flush_needed = -1;
unsigned int ssize, sets;
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index da349723d41..37357a599dc 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1170,7 +1170,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
config AMD_NUMA
def_bool y
prompt "Old style AMD Opteron NUMA detection"
- depends on NUMA && PCI
+ depends on X86_64 && NUMA && PCI
---help---
Enable AMD NUMA node topology detection. You should say Y here if
you have a multi processor AMD system. This uses an old method to
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 4f0d46fefa7..9242436e993 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -419,6 +419,30 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
},
},
+ { /* Handle problems with rebooting on the Latitude E6320. */
+ .callback = set_pci_reboot,
+ .ident = "Dell Latitude E6320",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
+ },
+ },
+ { /* Handle problems with rebooting on the Latitude E5420. */
+ .callback = set_pci_reboot,
+ .ident = "Dell Latitude E5420",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
+ },
+ },
+ { /* Handle problems with rebooting on the Latitude E6420. */
+ .callback = set_pci_reboot,
+ .ident = "Dell Latitude E6420",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
+ },
+ },
{ }
};
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 73863d86f02..76dc02f1557 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -126,6 +126,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
+/*
+ * Disable runtime checking and repair of values returned by control methods.
+ * Use only if the repair is causing a problem on a particular machine.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
+
/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
struct acpi_table_fadt acpi_gbl_FADT;
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index c7f743ca395..5552125d834 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -357,6 +357,7 @@ struct acpi_predefined_data {
char *pathname;
const union acpi_predefined_info *predefined;
union acpi_operand_object *parent_package;
+ struct acpi_namespace_node *node;
u32 flags;
u8 node_flags;
};
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 94e73c97cf8..c445cca490e 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -468,6 +468,7 @@ static const union acpi_predefined_info predefined_names[] =
{{"_SWS", 0, ACPI_RTYPE_INTEGER}},
{{"_TC1", 0, ACPI_RTYPE_INTEGER}},
{{"_TC2", 0, ACPI_RTYPE_INTEGER}},
+ {{"_TDL", 0, ACPI_RTYPE_INTEGER}},
{{"_TIP", 1, ACPI_RTYPE_INTEGER}},
{{"_TIV", 1, ACPI_RTYPE_INTEGER}},
{{"_TMP", 0, ACPI_RTYPE_INTEGER}},
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 9fb03fa8ffd..c845c8089f3 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -193,14 +193,20 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
}
/*
- * 1) We have a return value, but if one wasn't expected, just exit, this is
- * not a problem. For example, if the "Implicit Return" feature is
- * enabled, methods will always return a value.
+ * Return value validation and possible repair.
*
- * 2) If the return value can be of any type, then we cannot perform any
- * validation, exit.
+ * 1) Don't perform return value validation/repair if this feature
+ * has been disabled via a global option.
+ *
+ * 2) We have a return value, but if one wasn't expected, just exit,
+ * this is not a problem. For example, if the "Implicit Return"
+ * feature is enabled, methods will always return a value.
+ *
+ * 3) If the return value can be of any type, then we cannot perform
+ * any validation, just exit.
*/
- if ((!predefined->info.expected_btypes) ||
+ if (acpi_gbl_disable_auto_repair ||
+ (!predefined->info.expected_btypes) ||
(predefined->info.expected_btypes == ACPI_RTYPE_ALL)) {
goto cleanup;
}
@@ -212,6 +218,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
goto cleanup;
}
data->predefined = predefined;
+ data->node = node;
data->node_flags = node->flags;
data->pathname = pathname;
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 973883babee..024c4f263f8 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -503,6 +503,21 @@ acpi_ns_repair_TSS(struct acpi_predefined_data *data,
{
union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status;
+ struct acpi_namespace_node *node;
+
+ /*
+ * We can only sort the _TSS return package if there is no _PSS in the
+ * same scope. This is because if _PSS is present, the ACPI specification
+ * dictates that the _TSS Power Dissipation field is to be ignored, and
+ * therefore some BIOSs leave garbage values in the _TSS Power field(s).
+ * In this case, it is best to just return the _TSS package as-is.
+ * (May, 2011)
+ */
+ status =
+ acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK);
+ }
status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
ACPI_SORT_DESCENDING,
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 48db0944ce4..62365f6075d 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -126,12 +126,29 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
}
/*
- * Originally, we checked the table signature for "SSDT" or "PSDT" here.
- * Next, we added support for OEMx tables, signature "OEM".
- * Valid tables were encountered with a null signature, so we've just
- * given up on validating the signature, since it seems to be a waste
- * of code. The original code was removed (05/2008).
+ * Validate the incoming table signature.
+ *
+ * 1) Originally, we checked the table signature for "SSDT" or "PSDT".
+ * 2) We added support for OEMx tables, signature "OEM".
+ * 3) Valid tables were encountered with a null signature, so we just
+ * gave up on validating the signature, (05/2008).
+ * 4) We encountered non-AML tables such as the MADT, which caused
+ * interpreter errors and kernel faults. So now, we once again allow
+ * only "SSDT", "OEMx", and now, also a null signature. (05/2011).
*/
+ if ((table_desc->pointer->signature[0] != 0x00) &&
+ (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
+ && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) {
+ ACPI_ERROR((AE_INFO,
+ "Table has invalid signature [%4.4s] (0x%8.8X), must be SSDT or OEMx",
+ acpi_ut_valid_acpi_name(*(u32 *)table_desc->
+ pointer->
+ signature) ? table_desc->
+ pointer->signature : "????",
+ *(u32 *)table_desc->pointer->signature));
+
+ return_ACPI_STATUS(AE_BAD_SIGNATURE);
+ }
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index abda3786a5d..181bc2f7bb7 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -139,13 +139,23 @@ static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
{
struct platform_device *ghes_dev;
struct ghes_arr *ghes_arr = data;
- int rc;
+ int rc, i;
if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
return 0;
if (!((struct acpi_hest_generic *)hest_hdr)->enabled)
return 0;
+ for (i = 0; i < ghes_arr->count; i++) {
+ struct acpi_hest_header *hdr;
+ ghes_dev = ghes_arr->ghes_devs[i];
+ hdr = *(struct acpi_hest_header **)ghes_dev->dev.platform_data;
+ if (hdr->source_id == hest_hdr->source_id) {
+ pr_warning(FW_WARN HEST_PFX "Duplicated hardware error source ID: %d.\n",
+ hdr->source_id);
+ return -EIO;
+ }
+ }
ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id);
if (!ghes_dev)
return -ENOMEM;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index ffce2f06dd8..52720680190 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -870,7 +870,7 @@ DECLARE_FILE_FUNCTIONS(alarm);
}, \
}
-static struct battery_file {
+static const struct battery_file {
struct file_operations ops;
mode_t mode;
const char *name;
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 1864ad3cf89..19a61136d84 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -77,7 +77,7 @@ struct dock_dependent_device {
struct list_head list;
struct list_head hotplug_list;
acpi_handle handle;
- struct acpi_dock_ops *ops;
+ const struct acpi_dock_ops *ops;
void *context;
};
@@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
* the dock driver after _DCK is executed.
*/
int
-register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
+register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops,
void *context)
{
struct dock_dependent_device *dd;
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index 05b44201a61..22f918bacd3 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -92,7 +92,7 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
return count;
}
-static struct file_operations acpi_ec_io_ops = {
+static const struct file_operations acpi_ec_io_ops = {
.owner = THIS_MODULE,
.open = acpi_ec_open_io,
.read = acpi_ec_read_io,
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 467479f07c1..0f0356ca1a9 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -110,7 +110,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
return result;
}
-static struct thermal_cooling_device_ops fan_cooling_ops = {
+static const struct thermal_cooling_device_ops fan_cooling_ops = {
.get_max_state = fan_get_max_state,
.get_cur_state = fan_get_cur_state,
.set_cur_state = fan_set_cur_state,
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 52ca9649d76..fa32f584229 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -155,7 +155,7 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported)
{
if (!strcmp("Linux", interface)) {
- printk(KERN_NOTICE FW_BUG PREFIX
+ printk_once(KERN_NOTICE FW_BUG PREFIX
"BIOS _OSI(Linux) query %s%s\n",
osi_linux.enable ? "honored" : "ignored",
osi_linux.cmdline ? " via cmdline" :
@@ -237,8 +237,23 @@ void acpi_os_vprintf(const char *fmt, va_list args)
#endif
}
+#ifdef CONFIG_KEXEC
+static unsigned long acpi_rsdp;
+static int __init setup_acpi_rsdp(char *arg)
+{
+ acpi_rsdp = simple_strtoul(arg, NULL, 16);
+ return 0;
+}
+early_param("acpi_rsdp", setup_acpi_rsdp);
+#endif
+
acpi_physical_address __init acpi_os_get_root_pointer(void)
{
+#ifdef CONFIG_KEXEC
+ if (acpi_rsdp)
+ return acpi_rsdp;
+#endif
+
if (efi_enabled) {
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
return efi.acpi20;
@@ -1083,7 +1098,13 @@ struct osi_setup_entry {
bool enable;
};
-static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX];
+static struct osi_setup_entry __initdata
+ osi_setup_entries[OSI_STRING_ENTRIES_MAX] = {
+ {"Module Device", true},
+ {"Processor Device", true},
+ {"3.0 _SCP Extensions", true},
+ {"Processor Aggregator Device", true},
+};
void __init acpi_osi_setup(char *str)
{
@@ -1333,23 +1354,6 @@ int acpi_resources_are_enforced(void)
EXPORT_SYMBOL(acpi_resources_are_enforced);
/*
- * Create and initialize a spinlock.
- */
-acpi_status
-acpi_os_create_lock(acpi_spinlock *out_handle)
-{
- spinlock_t *lock;
-
- lock = ACPI_ALLOCATE(sizeof(spinlock_t));
- if (!lock)
- return AE_NO_MEMORY;
- spin_lock_init(lock);
- *out_handle = lock;
-
- return AE_OK;
-}
-
-/*
* Deallocate the memory for a spinlock.
*/
void acpi_os_delete_lock(acpi_spinlock handle)
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index f907cfbfa13..7f9eba9a0b0 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -303,6 +303,61 @@ void acpi_pci_irq_del_prt(struct pci_bus *bus)
/* --------------------------------------------------------------------------
PCI Interrupt Routing Support
-------------------------------------------------------------------------- */
+#ifdef CONFIG_X86_IO_APIC
+extern int noioapicquirk;
+extern int noioapicreroute;
+
+static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
+{
+ struct pci_bus *bus_it;
+
+ for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
+ if (!bus_it->self)
+ return 0;
+ if (bus_it->self->irq_reroute_variant)
+ return bus_it->self->irq_reroute_variant;
+ }
+ return 0;
+}
+
+/*
+ * Some chipsets (e.g. Intel 6700PXH) generate a legacy INTx when the IRQ
+ * entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel does
+ * during interrupt handling). When this INTx generation cannot be disabled,
+ * we reroute these interrupts to their legacy equivalent to get rid of
+ * spurious interrupts.
+ */
+static int acpi_reroute_boot_interrupt(struct pci_dev *dev,
+ struct acpi_prt_entry *entry)
+{
+ if (noioapicquirk || noioapicreroute) {
+ return 0;
+ } else {
+ switch (bridge_has_boot_interrupt_variant(dev->bus)) {
+ case 0:
+ /* no rerouting necessary */
+ return 0;
+ case INTEL_IRQ_REROUTE_VARIANT:
+ /*
+ * Remap according to INTx routing table in 6700PXH
+ * specs, intel order number 302628-002, section
+ * 2.15.2. Other chipsets (80332, ...) have the same
+ * mapping and are handled here as well.
+ */
+ dev_info(&dev->dev, "PCI IRQ %d -> rerouted to legacy "
+ "IRQ %d\n", entry->index,
+ (entry->index % 4) + 16);
+ entry->index = (entry->index % 4) + 16;
+ return 1;
+ default:
+ dev_warn(&dev->dev, "Cannot reroute IRQ %d to legacy "
+ "IRQ: unknown mapping\n", entry->index);
+ return -1;
+ }
+ }
+}
+#endif /* CONFIG_X86_IO_APIC */
+
static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
{
struct acpi_prt_entry *entry;
@@ -311,6 +366,9 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
entry = acpi_pci_irq_find_prt_entry(dev, pin);
if (entry) {
+#ifdef CONFIG_X86_IO_APIC
+ acpi_reroute_boot_interrupt(dev, entry);
+#endif /* CONFIG_X86_IO_APIC */
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n",
pci_name(dev), pin_name(pin)));
return entry;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index d06078d660a..2672c798272 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -485,7 +485,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
root->secondary.end = 0xFF;
printk(KERN_WARNING FW_BUG PREFIX
"no secondary bus range in _CRS\n");
- status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus);
+ status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,
+ NULL, &bus);
if (ACPI_SUCCESS(status))
root->secondary.start = bus;
else if (status == AE_NOT_FOUND)
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 79cb6533289..870550d6a4b 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -244,7 +244,7 @@ processor_set_cur_state(struct thermal_cooling_device *cdev,
return result;
}
-struct thermal_cooling_device_ops processor_cooling_ops = {
+const struct thermal_cooling_device_ops processor_cooling_ops = {
.get_max_state = processor_get_max_state,
.get_cur_state = processor_get_cur_state,
.set_cur_state = processor_set_cur_state,
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 51ae3794ec7..c517ec8106e 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -130,6 +130,9 @@ struct acpi_sbs {
#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
+static int acpi_sbs_remove(struct acpi_device *device, int type);
+static int acpi_battery_get_state(struct acpi_battery *battery);
+
static inline int battery_scale(int log)
{
int scale = 1;
@@ -195,6 +198,8 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy,
if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT)
return -ENODEV;
+
+ acpi_battery_get_state(battery);
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
if (battery->rate_now < 0)
@@ -225,11 +230,17 @@ static int acpi_sbs_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_POWER_NOW:
val->intval = abs(battery->rate_now) *
acpi_battery_ipscale(battery) * 1000;
+ val->intval *= (acpi_battery_mode(battery)) ?
+ (battery->voltage_now *
+ acpi_battery_vscale(battery) / 1000) : 1;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
case POWER_SUPPLY_PROP_POWER_AVG:
val->intval = abs(battery->rate_avg) *
acpi_battery_ipscale(battery) * 1000;
+ val->intval *= (acpi_battery_mode(battery)) ?
+ (battery->voltage_now *
+ acpi_battery_vscale(battery) / 1000) : 1;
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = battery->state_of_charge;
@@ -903,8 +914,6 @@ static void acpi_sbs_callback(void *context)
}
}
-static int acpi_sbs_remove(struct acpi_device *device, int type);
-
static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs;
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 6c949602cbd..3ed80b2ca90 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -428,6 +428,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
},
},
+ {
+ .callback = init_old_suspend_ordering,
+ .ident = "Asus A8N-SLI DELUXE",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"),
+ },
+ },
+ {
+ .callback = init_old_suspend_ordering,
+ .ident = "Asus A8N-SLI Premium",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 77255f250db..c538d0ef10f 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -149,12 +149,12 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
return result;
}
-static struct kernel_param_ops param_ops_debug_layer = {
+static const struct kernel_param_ops param_ops_debug_layer = {
.set = param_set_uint,
.get = param_get_debug_layer,
};
-static struct kernel_param_ops param_ops_debug_level = {
+static const struct kernel_param_ops param_ops_debug_level = {
.set = param_set_uint,
.get = param_get_debug_level,
};
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 2607e17b520..48fbc647b17 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -812,7 +812,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
thermal_zone_unbind_cooling_device);
}
-static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
+static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.bind = acpi_thermal_bind_cooling_device,
.unbind = acpi_thermal_unbind_cooling_device,
.get_temp = thermal_get_temp,
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index db39e9e607d..c6f9ef8d9cc 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -308,7 +308,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st
return acpi_video_device_lcd_set_level(video, level);
}
-static struct thermal_cooling_device_ops video_cooling_ops = {
+static const struct thermal_cooling_device_ops video_cooling_ops = {
.get_max_state = video_get_max_state,
.get_cur_state = video_get_cur_state,
.set_cur_state = video_set_cur_state,
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index a791b8ce629..993d40620f9 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -218,12 +218,12 @@ static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
ata_acpi_uevent(dev->link->ap, dev, event);
}
-static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
+static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
.handler = ata_acpi_dev_notify_dock,
.uevent = ata_acpi_dev_uevent,
};
-static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
+static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
.handler = ata_acpi_ap_notify_dock,
.uevent = ata_acpi_ap_uevent,
};
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 999803ce10d..5da67f165af 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -90,9 +90,10 @@
#define G4x_GMCH_SIZE_MASK (0xf << 8)
#define G4x_GMCH_SIZE_1M (0x1 << 8)
#define G4x_GMCH_SIZE_2M (0x3 << 8)
-#define G4x_GMCH_SIZE_VT_1M (0x9 << 8)
-#define G4x_GMCH_SIZE_VT_1_5M (0xa << 8)
-#define G4x_GMCH_SIZE_VT_2M (0xc << 8)
+#define G4x_GMCH_SIZE_VT_EN (0x8 << 8)
+#define G4x_GMCH_SIZE_VT_1M (G4x_GMCH_SIZE_1M | G4x_GMCH_SIZE_VT_EN)
+#define G4x_GMCH_SIZE_VT_1_5M ((0x2 << 8) | G4x_GMCH_SIZE_VT_EN)
+#define G4x_GMCH_SIZE_VT_2M (G4x_GMCH_SIZE_2M | G4x_GMCH_SIZE_VT_EN)
#define GFX_FLSH_CNTL 0x2170 /* 915+ */
diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c
index 309644cf4d9..2bcfb0be09f 100644
--- a/drivers/gpio/wm831x-gpio.c
+++ b/drivers/gpio/wm831x-gpio.c
@@ -180,6 +180,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
break;
case WM831X_GPIO_PULL_UP:
pull = "pullup";
+ break;
default:
pull = "INVALID PULL";
break;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f245c588ae9..ce7914c4c04 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -262,6 +262,7 @@ enum intel_pch {
};
#define QUIRK_PIPEA_FORCE (1<<0)
+#define QUIRK_LVDS_SSC_DISABLE (1<<1)
struct intel_fbdev;
@@ -1194,7 +1195,9 @@ void i915_gem_free_all_phys_object(struct drm_device *dev);
void i915_gem_release(struct drm_device *dev, struct drm_file *file);
uint32_t
-i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj);
+i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
+ uint32_t size,
+ int tiling_mode);
/* i915_gem_gtt.c */
void i915_gem_restore_gtt_mappings(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5c0d1247f45..a087e1bf0c2 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1374,25 +1374,24 @@ i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj)
}
static uint32_t
-i915_gem_get_gtt_size(struct drm_i915_gem_object *obj)
+i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode)
{
- struct drm_device *dev = obj->base.dev;
- uint32_t size;
+ uint32_t gtt_size;
if (INTEL_INFO(dev)->gen >= 4 ||
- obj->tiling_mode == I915_TILING_NONE)
- return obj->base.size;
+ tiling_mode == I915_TILING_NONE)
+ return size;
/* Previous chips need a power-of-two fence region when tiling */
if (INTEL_INFO(dev)->gen == 3)
- size = 1024*1024;
+ gtt_size = 1024*1024;
else
- size = 512*1024;
+ gtt_size = 512*1024;
- while (size < obj->base.size)
- size <<= 1;
+ while (gtt_size < size)
+ gtt_size <<= 1;
- return size;
+ return gtt_size;
}
/**
@@ -1403,59 +1402,52 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj)
* potential fence register mapping.
*/
static uint32_t
-i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj)
+i915_gem_get_gtt_alignment(struct drm_device *dev,
+ uint32_t size,
+ int tiling_mode)
{
- struct drm_device *dev = obj->base.dev;
-
/*
* Minimum alignment is 4k (GTT page size), but might be greater
* if a fence register is needed for the object.
*/
if (INTEL_INFO(dev)->gen >= 4 ||
- obj->tiling_mode == I915_TILING_NONE)
+ tiling_mode == I915_TILING_NONE)
return 4096;
/*
* Previous chips need to be aligned to the size of the smallest
* fence register that can contain the object.
*/
- return i915_gem_get_gtt_size(obj);
+ return i915_gem_get_gtt_size(dev, size, tiling_mode);
}
/**
* i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an
* unfenced object
- * @obj: object to check
+ * @dev: the device
+ * @size: size of the object
+ * @tiling_mode: tiling mode of the object
*
* Return the required GTT alignment for an object, only taking into account
* unfenced tiled surface requirements.
*/
uint32_t
-i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj)
+i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
+ uint32_t size,
+ int tiling_mode)
{
- struct drm_device *dev = obj->base.dev;
- int tile_height;
-
/*
* Minimum alignment is 4k (GTT page size) for sane hw.
*/
if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) ||
- obj->tiling_mode == I915_TILING_NONE)
+ tiling_mode == I915_TILING_NONE)
return 4096;
- /*
- * Older chips need unfenced tiled buffers to be aligned to the left
- * edge of an even tile row (where tile rows are counted as if the bo is
- * placed in a fenced gtt region).
+ /* Previous hardware however needs to be aligned to a power-of-two
+ * tile height. The simplest method for determining this is to reuse
+ * the power-of-tile object size.
*/
- if (IS_GEN2(dev))
- tile_height = 16;
- else if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
- tile_height = 32;
- else
- tile_height = 8;
-
- return tile_height * obj->stride * 2;
+ return i915_gem_get_gtt_size(dev, size, tiling_mode);
}
int
@@ -2744,9 +2736,16 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
return -EINVAL;
}
- fence_size = i915_gem_get_gtt_size(obj);
- fence_alignment = i915_gem_get_gtt_alignment(obj);
- unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj);
+ fence_size = i915_gem_get_gtt_size(dev,
+ obj->base.size,
+ obj->tiling_mode);
+ fence_alignment = i915_gem_get_gtt_alignment(dev,
+ obj->base.size,
+ obj->tiling_mode);
+ unfenced_alignment =
+ i915_gem_get_unfenced_gtt_alignment(dev,
+ obj->base.size,
+ obj->tiling_mode);
if (alignment == 0)
alignment = map_and_fenceable ? fence_alignment :
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 82d70fd9e93..99c4faa59d8 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -348,7 +348,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
/* Rebind if we need a change of alignment */
if (!obj->map_and_fenceable) {
u32 unfenced_alignment =
- i915_gem_get_unfenced_gtt_alignment(obj);
+ i915_gem_get_unfenced_gtt_alignment(dev,
+ obj->base.size,
+ args->tiling_mode);
if (obj->gtt_offset & (unfenced_alignment - 1))
ret = i915_gem_object_unbind(obj);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 21b6f93fe91..0f1c799afea 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4305,7 +4305,8 @@ static void intel_update_watermarks(struct drm_device *dev)
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
{
- return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
+ return dev_priv->lvds_use_ssc && i915_panel_use_ssc
+ && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
}
static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
@@ -7810,6 +7811,15 @@ static void quirk_pipea_force (struct drm_device *dev)
DRM_DEBUG_DRIVER("applying pipe a force quirk\n");
}
+/*
+ * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
+ */
+static void quirk_ssc_force_disable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE;
+}
+
struct intel_quirk {
int device;
int subsystem_vendor;
@@ -7838,6 +7848,9 @@ struct intel_quirk intel_quirks[] = {
/* 855 & before need to leave pipe A & dpll A up */
{ 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
{ 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+
+ /* Lenovo U160 cannot use SSC on LVDS */
+ { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
};
static void intel_init_quirks(struct drm_device *dev)
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 660f96401a0..15bd0477a3e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2000,7 +2000,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
gb_backend_map = 0x66442200;
break;
case CHIP_JUNIPER:
- gb_backend_map = 0x00006420;
+ gb_backend_map = 0x00002200;
break;
default:
gb_backend_map =
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
index 57f3bc17b87..2eb251858e7 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -252,7 +252,7 @@ draw_auto(struct radeon_device *rdev)
}
-/* emits 36 */
+/* emits 39 */
static void
set_default_state(struct radeon_device *rdev)
{
@@ -531,6 +531,11 @@ set_default_state(struct radeon_device *rdev)
radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
radeon_ring_write(rdev, 0);
+ /* setup LDS */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, (SQ_LDS_RESOURCE_MGMT - PACKET3_SET_CONFIG_REG_START) >> 2);
+ radeon_ring_write(rdev, 0x10001000);
+
/* SQ config */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
@@ -773,7 +778,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
/* calculate number of loops correctly */
ring_size = num_loops * dwords_per_loop;
/* set default + shaders */
- ring_size += 52; /* shaders + def state */
+ ring_size += 55; /* shaders + def state */
ring_size += 10; /* fence emit for VB IB */
ring_size += 5; /* done copy */
ring_size += 10; /* fence emit for done copy */
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 3fc5fa1aefd..229a20f10e2 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -331,7 +331,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev)
seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ bus_cntl = RREG32(RV370_BUS_CNTL);
d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
@@ -350,7 +350,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev)
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
/* Disable VGA mode */
WREG32(AVIVO_D1VGA_CONTROL,
@@ -367,7 +367,7 @@ static bool avivo_read_disabled_bios(struct radeon_device *rdev)
/* restore regs */
WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ WREG32(RV370_BUS_CNTL, bus_cntl);
WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
@@ -390,7 +390,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
viph_control = RREG32(RADEON_VIPH_CONTROL);
- bus_cntl = RREG32(RADEON_BUS_CNTL);
+ if (rdev->flags & RADEON_IS_PCIE)
+ bus_cntl = RREG32(RV370_BUS_CNTL);
+ else
+ bus_cntl = RREG32(RADEON_BUS_CNTL);
crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
crtc2_gen_cntl = 0;
crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
@@ -412,7 +415,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
/* enable the rom */
- WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+ if (rdev->flags & RADEON_IS_PCIE)
+ WREG32(RV370_BUS_CNTL, (bus_cntl & ~RV370_BUS_BIOS_DIS_ROM));
+ else
+ WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
/* Turn off mem requests and CRTC for both controllers */
WREG32(RADEON_CRTC_GEN_CNTL,
@@ -439,7 +445,10 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
/* restore regs */
WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
WREG32(RADEON_VIPH_CONTROL, viph_control);
- WREG32(RADEON_BUS_CNTL, bus_cntl);
+ if (rdev->flags & RADEON_IS_PCIE)
+ WREG32(RV370_BUS_CNTL, bus_cntl);
+ else
+ WREG32(RADEON_BUS_CNTL, bus_cntl);
WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index cbfca3a24fd..9792d4ffdc8 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -52,6 +52,12 @@ void radeon_connector_hotplug(struct drm_connector *connector)
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ /* bail if the connector does not have hpd pin, e.g.,
+ * VGA, TV, etc.
+ */
+ if (radeon_connector->hpd.hpd == RADEON_HPD_NONE)
+ return;
+
radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
/* powering up/down the eDP panel generates hpd events which
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h