drm/i915: Add support for the G33, Q33, and Q35 chipsets.

These require that the status page be referenced by a pointer in GTT, rather
than phsyical memory. So, we have the X Server allocate that memory and tell
us the address, instead.

Signed-off-by: Dave Airlie <airlied@linux.ie>

authored by Wang Zhenyu and committed by Dave Airlie dc7a9319 2f4042b1

+80 -17
+3
drivers/char/drm/drm_pciids.h
··· 305 305 {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 306 306 {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 307 307 {0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 308 + {0x8086, 0x29b2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 309 + {0x8086, 0x29c2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 310 + {0x8086, 0x29d2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 308 311 {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 309 312 {0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ 310 313 {0, 0, 0}
+70 -17
drivers/char/drm/i915_dma.c
··· 38 38 dev->pci_device == 0x2A02 || \ 39 39 dev->pci_device == 0x2A12) 40 40 41 + #define IS_G33(dev) (dev->pci_device == 0x29b2 || \ 42 + dev->pci_device == 0x29c2 || \ 43 + dev->pci_device == 0x29d2) 44 + 41 45 /* Really want an OS-independent resettable timer. Would like to have 42 46 * this loop run for (eg) 3 sec, but have the timer reset every time 43 47 * the head pointer changes, so that EBUSY only happens if the ring ··· 109 105 drm_pci_free(dev, dev_priv->status_page_dmah); 110 106 /* Need to rewrite hardware status page */ 111 107 I915_WRITE(0x02080, 0x1ffff000); 108 + } 109 + 110 + if (dev_priv->status_gfx_addr) { 111 + dev_priv->status_gfx_addr = 0; 112 + drm_core_ioremapfree(&dev_priv->hws_map, dev); 113 + I915_WRITE(0x2080, 0x1ffff000); 112 114 } 113 115 114 116 drm_free(dev->dev_private, sizeof(drm_i915_private_t), ··· 190 180 dev_priv->allow_batchbuffer = 1; 191 181 192 182 /* Program Hardware Status Page */ 193 - dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 194 - 0xffffffff); 183 + if (!IS_G33(dev)) { 184 + dev_priv->status_page_dmah = 185 + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); 195 186 196 - if (!dev_priv->status_page_dmah) { 197 - dev->dev_private = (void *)dev_priv; 198 - i915_dma_cleanup(dev); 199 - DRM_ERROR("Can not allocate hardware status page\n"); 200 - return DRM_ERR(ENOMEM); 187 + if (!dev_priv->status_page_dmah) { 188 + dev->dev_private = (void *)dev_priv; 189 + i915_dma_cleanup(dev); 190 + DRM_ERROR("Can not allocate hardware status page\n"); 191 + return DRM_ERR(ENOMEM); 192 + } 193 + dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; 194 + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; 195 + 196 + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); 197 + I915_WRITE(0x02080, dev_priv->dma_status_page); 201 198 } 202 - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; 203 - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; 204 - 205 - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); 206 - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); 207 - 208 - I915_WRITE(0x02080, dev_priv->dma_status_page); 209 199 DRM_DEBUG("Enabled hardware status page\n"); 210 - 211 200 dev->dev_private = (void *)dev_priv; 212 - 213 201 return 0; 214 202 } 215 203 ··· 240 232 } 241 233 DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); 242 234 243 - I915_WRITE(0x02080, dev_priv->dma_status_page); 235 + if (dev_priv->status_gfx_addr != 0) 236 + I915_WRITE(0x02080, dev_priv->status_gfx_addr); 237 + else 238 + I915_WRITE(0x02080, dev_priv->dma_status_page); 244 239 DRM_DEBUG("Enabled hardware status page\n"); 245 240 246 241 return 0; ··· 751 740 return 0; 752 741 } 753 742 743 + static int i915_set_status_page(DRM_IOCTL_ARGS) 744 + { 745 + DRM_DEVICE; 746 + drm_i915_private_t *dev_priv = dev->dev_private; 747 + drm_i915_hws_addr_t hws; 748 + 749 + if (!dev_priv) { 750 + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 751 + return DRM_ERR(EINVAL); 752 + } 753 + DRM_COPY_FROM_USER_IOCTL(hws, (drm_i915_hws_addr_t __user *) data, 754 + sizeof(hws)); 755 + printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws.addr); 756 + 757 + dev_priv->status_gfx_addr = hws.addr & (0x1ffff<<12); 758 + 759 + dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws.addr; 760 + dev_priv->hws_map.size = 4*1024; 761 + dev_priv->hws_map.type = 0; 762 + dev_priv->hws_map.flags = 0; 763 + dev_priv->hws_map.mtrr = 0; 764 + 765 + drm_core_ioremap(&dev_priv->hws_map, dev); 766 + if (dev_priv->hws_map.handle == NULL) { 767 + dev->dev_private = (void *)dev_priv; 768 + i915_dma_cleanup(dev); 769 + dev_priv->status_gfx_addr = 0; 770 + DRM_ERROR("can not ioremap virtual address for" 771 + " G33 hw status page\n"); 772 + return DRM_ERR(ENOMEM); 773 + } 774 + dev_priv->hw_status_page = dev_priv->hws_map.handle; 775 + 776 + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); 777 + I915_WRITE(0x02080, dev_priv->status_gfx_addr); 778 + DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", 779 + dev_priv->status_gfx_addr); 780 + DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); 781 + return 0; 782 + } 783 + 754 784 int i915_driver_load(drm_device_t *dev, unsigned long flags) 755 785 { 756 786 /* i915 has 4 more counters */ ··· 838 786 [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, 839 787 [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, 840 788 [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, 789 + [DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] = {i915_set_status_page, DRM_AUTH}, 841 790 }; 842 791 843 792 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
+5
drivers/char/drm/i915_drm.h
··· 142 142 #define DRM_I915_SET_VBLANK_PIPE 0x0d 143 143 #define DRM_I915_GET_VBLANK_PIPE 0x0e 144 144 #define DRM_I915_VBLANK_SWAP 0x0f 145 + #define DRM_I915_HWS_ADDR 0x11 145 146 146 147 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) 147 148 #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) ··· 262 261 drm_vblank_seq_type_t seqtype; 263 262 unsigned int sequence; 264 263 } drm_i915_vblank_swap_t; 264 + 265 + typedef struct drm_i915_hws_addr { 266 + uint64_t addr; 267 + } drm_i915_hws_addr_t; 265 268 266 269 #endif /* _I915_DRM_H_ */
+2
drivers/char/drm/i915_drv.h
··· 91 91 void *hw_status_page; 92 92 dma_addr_t dma_status_page; 93 93 unsigned long counter; 94 + unsigned int status_gfx_addr; 95 + drm_local_map_t hws_map; 94 96 95 97 unsigned int cpp; 96 98 int back_offset;