diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 43 | ||||
-rw-r--r-- | drivers/video/fbmem.c | 43 | ||||
-rw-r--r-- | include/linux/fb.h | 1 |
5 files changed, 71 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5b47b79f45e8..94d8dd27bde8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -624,6 +624,7 @@ struct drm_nouveau_private { | |||
624 | } debugfs; | 624 | } debugfs; |
625 | 625 | ||
626 | struct nouveau_fbdev *nfbdev; | 626 | struct nouveau_fbdev *nfbdev; |
627 | struct apertures_struct *apertures; | ||
627 | }; | 628 | }; |
628 | 629 | ||
629 | static inline struct drm_nouveau_private * | 630 | static inline struct drm_nouveau_private * |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 292c7ff95105..2c2199329cc1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c | |||
@@ -183,7 +183,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, | |||
183 | struct drm_mode_fb_cmd mode_cmd; | 183 | struct drm_mode_fb_cmd mode_cmd; |
184 | struct pci_dev *pdev = dev->pdev; | 184 | struct pci_dev *pdev = dev->pdev; |
185 | struct device *device = &pdev->dev; | 185 | struct device *device = &pdev->dev; |
186 | struct apertures_struct *aper; | ||
187 | int size, ret; | 186 | int size, ret; |
188 | 187 | ||
189 | mode_cmd.width = sizes->surface_width; | 188 | mode_cmd.width = sizes->surface_width; |
@@ -267,28 +266,12 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, | |||
267 | info->fix.mmio_len = pci_resource_len(pdev, 1); | 266 | info->fix.mmio_len = pci_resource_len(pdev, 1); |
268 | 267 | ||
269 | /* Set aperture base/size for vesafb takeover */ | 268 | /* Set aperture base/size for vesafb takeover */ |
270 | aper = info->apertures = alloc_apertures(3); | 269 | info->apertures = dev_priv->apertures; |
271 | if (!info->apertures) { | 270 | if (!info->apertures) { |
272 | ret = -ENOMEM; | 271 | ret = -ENOMEM; |
273 | goto out_unref; | 272 | goto out_unref; |
274 | } | 273 | } |
275 | 274 | ||
276 | aper->ranges[0].base = pci_resource_start(pdev, 1); | ||
277 | aper->ranges[0].size = pci_resource_len(pdev, 1); | ||
278 | aper->count = 1; | ||
279 | |||
280 | if (pci_resource_len(pdev, 2)) { | ||
281 | aper->ranges[aper->count].base = pci_resource_start(pdev, 2); | ||
282 | aper->ranges[aper->count].size = pci_resource_len(pdev, 2); | ||
283 | aper->count++; | ||
284 | } | ||
285 | |||
286 | if (pci_resource_len(pdev, 3)) { | ||
287 | aper->ranges[aper->count].base = pci_resource_start(pdev, 3); | ||
288 | aper->ranges[aper->count].size = pci_resource_len(pdev, 3); | ||
289 | aper->count++; | ||
290 | } | ||
291 | |||
292 | info->pixmap.size = 64*1024; | 275 | info->pixmap.size = 64*1024; |
293 | info->pixmap.buf_align = 8; | 276 | info->pixmap.buf_align = 8; |
294 | info->pixmap.access_align = 32; | 277 | info->pixmap.access_align = 32; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 92100a9678ba..75c5c465e08e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -639,6 +639,43 @@ static void nouveau_OF_copy_vbios_to_ramin(struct drm_device *dev) | |||
639 | #endif | 639 | #endif |
640 | } | 640 | } |
641 | 641 | ||
642 | static struct apertures_struct *nouveau_get_apertures(struct drm_device *dev) | ||
643 | { | ||
644 | struct pci_dev *pdev = dev->pdev; | ||
645 | struct apertures_struct *aper = alloc_apertures(3); | ||
646 | if (!aper) | ||
647 | return NULL; | ||
648 | |||
649 | aper->ranges[0].base = pci_resource_start(pdev, 1); | ||
650 | aper->ranges[0].size = pci_resource_len(pdev, 1); | ||
651 | aper->count = 1; | ||
652 | |||
653 | if (pci_resource_len(pdev, 2)) { | ||
654 | aper->ranges[aper->count].base = pci_resource_start(pdev, 2); | ||
655 | aper->ranges[aper->count].size = pci_resource_len(pdev, 2); | ||
656 | aper->count++; | ||
657 | } | ||
658 | |||
659 | if (pci_resource_len(pdev, 3)) { | ||
660 | aper->ranges[aper->count].base = pci_resource_start(pdev, 3); | ||
661 | aper->ranges[aper->count].size = pci_resource_len(pdev, 3); | ||
662 | aper->count++; | ||
663 | } | ||
664 | |||
665 | return aper; | ||
666 | } | ||
667 | |||
668 | static int nouveau_remove_conflicting_drivers(struct drm_device *dev) | ||
669 | { | ||
670 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
671 | dev_priv->apertures = nouveau_get_apertures(dev); | ||
672 | if (!dev_priv->apertures) | ||
673 | return -ENOMEM; | ||
674 | |||
675 | remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb"); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
642 | int nouveau_load(struct drm_device *dev, unsigned long flags) | 679 | int nouveau_load(struct drm_device *dev, unsigned long flags) |
643 | { | 680 | { |
644 | struct drm_nouveau_private *dev_priv; | 681 | struct drm_nouveau_private *dev_priv; |
@@ -726,6 +763,12 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) | |||
726 | NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", | 763 | NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", |
727 | dev_priv->card_type, reg0); | 764 | dev_priv->card_type, reg0); |
728 | 765 | ||
766 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
767 | int ret = nouveau_remove_conflicting_drivers(dev); | ||
768 | if (ret) | ||
769 | return ret; | ||
770 | } | ||
771 | |||
729 | /* map larger RAMIN aperture on NV40 cards */ | 772 | /* map larger RAMIN aperture on NV40 cards */ |
730 | dev_priv->ramin = NULL; | 773 | dev_priv->ramin = NULL; |
731 | if (dev_priv->card_type >= NV_40) { | 774 | if (dev_priv->card_type >= NV_40) { |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 03f2dc2470b5..7cfcd716fd5f 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -1479,11 +1479,10 @@ static bool apertures_overlap(struct aperture *gen, struct aperture *hw) | |||
1479 | return false; | 1479 | return false; |
1480 | } | 1480 | } |
1481 | 1481 | ||
1482 | static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) | 1482 | static bool fb_do_apertures_overlap(struct apertures_struct *gena, |
1483 | struct apertures_struct *hwa) | ||
1483 | { | 1484 | { |
1484 | int i, j; | 1485 | int i, j; |
1485 | struct apertures_struct *hwa = hw->apertures; | ||
1486 | struct apertures_struct *gena = gen->apertures; | ||
1487 | if (!hwa || !gena) | 1486 | if (!hwa || !gena) |
1488 | return false; | 1487 | return false; |
1489 | 1488 | ||
@@ -1501,6 +1500,28 @@ static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) | |||
1501 | return false; | 1500 | return false; |
1502 | } | 1501 | } |
1503 | 1502 | ||
1503 | void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name) | ||
1504 | { | ||
1505 | int i; | ||
1506 | |||
1507 | /* check all firmware fbs and kick off if the base addr overlaps */ | ||
1508 | for (i = 0 ; i < FB_MAX; i++) { | ||
1509 | if (!registered_fb[i]) | ||
1510 | continue; | ||
1511 | |||
1512 | if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) | ||
1513 | continue; | ||
1514 | |||
1515 | if (fb_do_apertures_overlap(registered_fb[i]->apertures, a)) { | ||
1516 | printk(KERN_ERR "fb: conflicting fb hw usage " | ||
1517 | "%s vs %s - removing generic driver\n", | ||
1518 | name, registered_fb[i]->fix.id); | ||
1519 | unregister_framebuffer(registered_fb[i]); | ||
1520 | } | ||
1521 | } | ||
1522 | } | ||
1523 | EXPORT_SYMBOL(remove_conflicting_framebuffers); | ||
1524 | |||
1504 | /** | 1525 | /** |
1505 | * register_framebuffer - registers a frame buffer device | 1526 | * register_framebuffer - registers a frame buffer device |
1506 | * @fb_info: frame buffer info structure | 1527 | * @fb_info: frame buffer info structure |
@@ -1524,21 +1545,7 @@ register_framebuffer(struct fb_info *fb_info) | |||
1524 | if (fb_check_foreignness(fb_info)) | 1545 | if (fb_check_foreignness(fb_info)) |
1525 | return -ENOSYS; | 1546 | return -ENOSYS; |
1526 | 1547 | ||
1527 | /* check all firmware fbs and kick off if the base addr overlaps */ | 1548 | remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id); |
1528 | for (i = 0 ; i < FB_MAX; i++) { | ||
1529 | if (!registered_fb[i]) | ||
1530 | continue; | ||
1531 | |||
1532 | if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) { | ||
1533 | if (fb_do_apertures_overlap(registered_fb[i], fb_info)) { | ||
1534 | printk(KERN_ERR "fb: conflicting fb hw usage " | ||
1535 | "%s vs %s - removing generic driver\n", | ||
1536 | fb_info->fix.id, | ||
1537 | registered_fb[i]->fix.id); | ||
1538 | unregister_framebuffer(registered_fb[i]); | ||
1539 | } | ||
1540 | } | ||
1541 | } | ||
1542 | 1549 | ||
1543 | num_registered_fb++; | 1550 | num_registered_fb++; |
1544 | for (i = 0 ; i < FB_MAX; i++) | 1551 | for (i = 0 ; i < FB_MAX; i++) |
diff --git a/include/linux/fb.h b/include/linux/fb.h index de5ff5fa8380..f88e2549123d 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -971,6 +971,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, | |||
971 | /* drivers/video/fbmem.c */ | 971 | /* drivers/video/fbmem.c */ |
972 | extern int register_framebuffer(struct fb_info *fb_info); | 972 | extern int register_framebuffer(struct fb_info *fb_info); |
973 | extern int unregister_framebuffer(struct fb_info *fb_info); | 973 | extern int unregister_framebuffer(struct fb_info *fb_info); |
974 | extern void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name); | ||
974 | extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); | 975 | extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); |
975 | extern int fb_show_logo(struct fb_info *fb_info, int rotate); | 976 | extern int fb_show_logo(struct fb_info *fb_info, int rotate); |
976 | extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); | 977 | extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); |