# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/02/15 18:41:32-08:00 jgarzik@pobox.com # [PATCH] Update mac network drivers # # This should merge up the final piece of the ppc32/64 saga: the mac # PowerMac MACE and Airport network drivers. # # Both of them are ported to the mac-io infrastructure, all probe code # rewritting & cleaned up, better error handling & resource management. # # drivers/net/wireless/airport.c # 2004/02/15 09:45:08-08:00 jgarzik@pobox.com +23 -28 # Update mac network drivers # # drivers/net/mace.c # 2004/02/15 09:45:08-08:00 jgarzik@pobox.com +145 -96 # Update mac network drivers # # ChangeSet # 2004/02/15 18:14:15-08:00 torvalds@home.osdl.org # Fix radeonfb to use the proper BIOS reference divider for # flat-panel displays. # # From: Benjamin Herrenschmidt # # drivers/video/aty/radeon_base.c # 2004/02/15 18:14:11-08:00 torvalds@home.osdl.org +1 -1 # Fix radeonfb to use the proper BIOS reference divider for # flat-panel displays. # # ChangeSet # 2004/02/15 17:57:16-08:00 benh@kernel.crashing.org # [PATCH] fix radeonfb "noaccel" command line # # Fix proper detection of the "noaccel" command line argument for # new radeonfb so we can boot without acceleration. Useful when # diagnosing an accel-related problem. # # drivers/video/aty/radeon_base.c # 2004/02/15 09:35:13-08:00 benh@kernel.crashing.org +1 -1 # fix radeonfb "noaccel" command line # # ChangeSet # 2004/02/15 16:46:59-08:00 torvalds@evo.osdl.org # Fix user-visible typo in printk. # # Somebody has been watching lord of the rings a bit too # much.. "My precioussssss.." # # drivers/video/aty/radeon_monitor.c # 2004/02/15 16:46:53-08:00 torvalds@evo.osdl.org +1 -1 # Fix user-visible typo in printk. # # Somebody has been watching lord of the rings a bit too # much.. "My precioussssss.." # # ChangeSet # 2004/02/15 14:25:38-08:00 torvalds@evo.osdl.org # Fix new radeon clock calculation. # # From Peter Osterlund # # This code only ends up being used when all else fails, # so probably very few people actually ever saw this. # # drivers/video/aty/radeon_base.c # 2004/02/15 14:25:31-08:00 torvalds@evo.osdl.org +3 -2 # Fix new radeon clock calculation. # # From Peter Osterlund # # This code only ends up being used when all else fails, # so probably very few people actually ever saw this. # # drivers/video/console/fbcon.c # 2004/02/15 10:22:04-08:00 benh@kernel.crashing.org +52 -0 # fbcon notified of suspend/resume # # include/video/aty128.h # 2004/02/15 10:03:31-08:00 benh@kernel.crashing.org +3 -0 # Update aty128fb video driver # # include/linux/pci_ids.h # 2004/02/15 10:03:31-08:00 benh@kernel.crashing.org +24 -15 # Update aty128fb video driver # # drivers/video/aty/aty128fb.c # 2004/02/15 10:03:31-08:00 benh@kernel.crashing.org +569 -458 # Update aty128fb video driver # # ChangeSet # 2004/02/15 09:34:26-08:00 petero2@telia.com # [PATCH] Missing initialization code for old radeon driver # # You can still build the old driver, but it doesn't work unless you also # enable it like this.. # # drivers/video/fbmem.c # 2004/02/15 02:43:42-08:00 petero2@telia.com +3 -0 # Missing initialization code for old radeon driver # # ChangeSet # 2004/02/15 09:33:50-08:00 benh@kernel.crashing.org # [PATCH] fbcon notified of suspend/resume # # This makes fbcon ask for notification of events from fbdev to deal with # suspend/resume (stop cursor on suspend, refresh screen on resume). # Could probably do more (like dealing better with the cursor timer), but # this simple implementation works fine enough for now. # # ChangeSet # 2004/02/15 09:33:19-08:00 benh@kernel.crashing.org # [PATCH] fbdev state management # # This adds some "state" information for power management to fbdev's, # along with a notifier mecanism to inform clients of state changes. It # also "uses" this mecanism in the function fb_set_suspend() which was an # empty placeholder previously, and "shields" various places that access # the HW when state isn't running. (It's best to not call them in the # first place, but the current state of fbcon makes that _very_ difficult) # # include/linux/fb.h # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +21 -0 # fbdev state management # # drivers/video/softcursor.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0 # fbdev state management # # drivers/video/fbmem.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +47 -2 # fbdev state management # # drivers/video/console/fbcon.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +8 -2 # fbdev state management # # drivers/video/cfbimgblt.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0 # fbdev state management # # drivers/video/cfbfillrect.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0 # fbdev state management # # drivers/video/cfbcopyarea.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0 # fbdev state management # # drivers/video/aty/radeon_accel.c # 2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +4 -4 # fbdev state management # # ChangeSet # 2004/02/15 09:32:46-08:00 benh@kernel.crashing.org # [PATCH] Update aty128fb video driver # # This updates the aty128fb driver. It adds more PCI IDs, uses the new # framebuffer alloc/release functions, make BIOS PLL data access more # reliable (using ROM whenever possible, with a fallback to RAM BIOS # image), cleanup the Power Management stuff (get rid of PowerMac specific # stuffs, use real PCI ones instead), along with some style cleanups # # ChangeSet # 2004/02/15 09:32:22-08:00 benh@kernel.crashing.org # [PATCH] Fix fbdev pixmap locking # # This removes the broken locking code in the pixmaps, and rewrite the # buffer access function to properly call fb_sync when needed. The old # broken loocking is useless as we are covered by the console semaphore in # all cases hopefully (except if I missed one :) # # include/linux/fb.h # 2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +0 -2 # Fix fbdev pixmap locking # # drivers/video/softcursor.c # 2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +0 -2 # Fix fbdev pixmap locking # # drivers/video/fbmem.c # 2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +21 -15 # Fix fbdev pixmap locking # # drivers/video/console/fbcon.c # 2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +0 -6 # Fix fbdev pixmap locking # # ChangeSet # 2004/02/15 09:32:00-08:00 benh@kernel.crashing.org # [PATCH] shield fbdev operations with console semaphore # # This fixes the fbdev ioctl's and fbcon cursor management with the # console semaphore, which is the best we can do at this point in 2.6, # thus fixing a bunch of races where we could have, for example, tried to # blit while changing mode, etc.. # # drivers/video/fbmem.c # 2004/02/15 09:04:36-08:00 benh@kernel.crashing.org +16 -4 # shield fbdev operations with console semaphore # # drivers/video/console/fbcon.c # 2004/02/15 09:04:36-08:00 benh@kernel.crashing.org +4 -3 # shield fbdev operations with console semaphore # # ChangeSet # 2004/02/15 09:31:44-08:00 benh@kernel.crashing.org # [PATCH] Fix Oops & warning on PPC in rivafb # # Independently from the other fbdev updates I'm cooking (some of them # will be in your mailbox rsn), this fixes an error in parameter passing # to a function in rivafb (only used on ppc) that could cause an oops and # definitely causes a warning at compile time. # # drivers/video/riva/fbdev.c # 2004/02/15 09:12:03-08:00 benh@kernel.crashing.org +2 -1 # Fix Oops & warning on PPC in rivafb # # ChangeSet # 2004/02/15 09:31:30-08:00 benh@kernel.crashing.org # [PATCH] Remove debug cruft from via-pmu.c driver # # drivers/macintosh/via-pmu.c # 2004/02/15 09:14:06-08:00 benh@kernel.crashing.org +0 -51 # Remove debug cruft from via-pmu.c driver # # ChangeSet # 2004/02/15 09:31:18-08:00 rusty@rustcorp.com.au # [PATCH] Sparc no longer F*cked Up # # From: Keith M Wesolowski # # As of 2.6.3, restore_flags will no longer modify cwp on sparc. # Therefore you can apply this patch to the locking guide. # # [ Indeed. I'll also remove the atomic comments from Hacking # Guide as part of my revision there when I get back to it. --RR ] # # Documentation/DocBook/kernel-locking.tmpl # 2004/02/08 07:07:26-08:00 rusty@rustcorp.com.au +0 -21 # Sparc no longer F*cked Up # # ChangeSet # 2004/02/15 16:47:56+01:00 marcel@holtmann.org # [Bluetooth] Revert reference counting fixes # # The RFCOMM TTY code don't leak reference counting, because the TTY layer # will call the ->close() method even if open fails and the reference count # is decreased there. # # Patch from David Woodhouse # # net/bluetooth/rfcomm/tty.c # 2004/02/15 16:47:12+01:00 marcel@holtmann.org +27 -10 # Revert reference counting fixes # diff -Nru a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl --- a/Documentation/DocBook/kernel-locking.tmpl Sun Feb 15 23:14:38 2004 +++ b/Documentation/DocBook/kernel-locking.tmpl Sun Feb 15 23:14:38 2004 @@ -1444,27 +1444,6 @@ - - The Fucked Up Sparc - - - Alan Cox says the irq disable/enable is in the register - window on a sparc. Andi Kleen says when you do - restore_flags in a different function you mess up all the - register windows. - - - - So never pass the flags word set by - spin_lock_irqsave() and brethren to another - function (unless it's declared inline). Usually no-one - does this, but now you've been warned. Dave Miller can never do - anything in a straightforward manner (I can say that, because I have - pictures of him and a certain PowerPC maintainer in a compromising - position). - - - diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c --- a/drivers/macintosh/via-pmu.c Sun Feb 15 23:14:38 2004 +++ b/drivers/macintosh/via-pmu.c Sun Feb 15 23:14:38 2004 @@ -72,13 +72,6 @@ /* How many iterations between battery polls */ #define BATTERY_POLLING_COUNT 2 -/* Some debugging tools */ -#ifdef CONFIG_XMON -//#define LIVE_DEBUG(req) ((req) && (req)->data[0] == 0x7d) -#define LIVE_DEBUG(req) (0) -static int whacky_debug; -#endif /* CONFIG_XMON */ - static volatile unsigned char *via; /* VIA registers - spaced 0x200 bytes apart */ @@ -1218,12 +1211,6 @@ wait_for_ack(); /* set the shift register to shift out and send a byte */ send_byte(req->data[0]); -#ifdef CONFIG_XMON - if (LIVE_DEBUG(req)) - xmon_printf("R"); - else - whacky_debug = 0; -#endif /* CONFIG_XMON */ } void __openfirmware @@ -1476,29 +1463,17 @@ case sending: req = current_req; if (data_len < 0) { -#ifdef CONFIG_XMON - if (LIVE_DEBUG(req)) - xmon_printf("s"); -#endif /* CONFIG_XMON */ data_len = req->nbytes - 1; send_byte(data_len); break; } if (data_index <= data_len) { -#ifdef CONFIG_XMON - if (LIVE_DEBUG(req)) - xmon_printf("S"); -#endif /* CONFIG_XMON */ send_byte(req->data[data_index++]); break; } req->sent = 1; data_len = pmu_data_len[req->data[0]][1]; if (data_len == 0) { -#ifdef CONFIG_XMON - if (LIVE_DEBUG(req)) - xmon_printf("D"); -#endif /* CONFIG_XMON */ pmu_state = idle; current_req = req->next; if (req->reply_expected) @@ -1506,10 +1481,6 @@ else return req; } else { -#ifdef CONFIG_XMON - if (LIVE_DEBUG(req)) - xmon_printf("-"); -#endif /* CONFIG_XMON */ pmu_state = reading; data_index = 0; reply_ptr = req->reply + req->reply_len; @@ -1532,18 +1503,10 @@ case reading: case reading_intr: if (data_len == -1) { -#ifdef CONFIG_XMON - if (LIVE_DEBUG(current_req)) - xmon_printf("r"); -#endif /* CONFIG_XMON */ data_len = bite; if (bite > 32) printk(KERN_ERR "PMU: bad reply len %d\n", bite); } else if (data_index < 32) { -#ifdef CONFIG_XMON - if (LIVE_DEBUG(current_req)) - xmon_printf("R"); -#endif /* CONFIG_XMON */ reply_ptr[data_index++] = bite; } if (data_index < data_len) { @@ -1551,12 +1514,6 @@ break; } -#ifdef CONFIG_XMON - if (LIVE_DEBUG(current_req)) { - whacky_debug = 1; - xmon_printf("D"); - } -#endif /* CONFIG_XMON */ if (pmu_state == reading_intr) { pmu_state = idle; int_data_state[int_data_last] = int_data_ready; @@ -1603,10 +1560,6 @@ intr = in_8(&via[IFR]) & (SR_INT | CB1_INT); if (intr == 0) break; -#ifdef CONFIG_XMON - if (whacky_debug) - xmon_printf("|%02x|", intr); -#endif /* CONFIG_XMON */ handled = 1; if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " @@ -1629,10 +1582,6 @@ recheck: if (pmu_state == idle) { if (adb_int_pending) { -#ifdef CONFIG_XMON - if (whacky_debug) - xmon_printf("!A!"); -#endif /* CONFIG_XMON */ if (int_data_state[0] == int_data_empty) int_data_last = 0; else if (int_data_state[1] == int_data_empty) diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c --- a/drivers/net/mace.c Sun Feb 15 23:14:38 2004 +++ b/drivers/net/mace.c Sun Feb 15 23:14:38 2004 @@ -20,9 +20,10 @@ #include #include #include +#include + #include "mace.h" -static struct net_device *mace_devs; static int port_aaui = -1; #define N_RX_RING 8 @@ -61,8 +62,7 @@ int timeout_active; int port_aaui; int chipid; - struct device_node* of_node; - struct net_device *next_mace; + struct macio_dev *mdev; spinlock_t lock; }; @@ -76,8 +76,6 @@ + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd)) static int bitrev(int); -static int mace_probe(void); -static void mace_probe1(struct device_node *mace); static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); @@ -110,26 +108,19 @@ return d; } -static int __init mace_probe(void) -{ - struct device_node *mace; - - for (mace = find_devices("mace"); mace != NULL; mace = mace->next) - mace_probe1(mace); - return mace_devs? 0: -ENODEV; -} -static void __init mace_probe1(struct device_node *mace) +static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match) { - int j, rev; + struct device_node *mace = macio_get_of_node(mdev); struct net_device *dev; struct mace_data *mp; unsigned char *addr; + int j, rev, rc = -EBUSY; - if (mace->n_addrs != 3 || mace->n_intrs != 3) { + if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", mace->full_name); - return; + return -ENODEV; } addr = get_property(mace, "mac-address", NULL); @@ -138,48 +129,48 @@ if (addr == NULL) { printk(KERN_ERR "Can't get mac-address for MACE %s\n", mace->full_name); - return; + return -ENODEV; } } /* - * lazy allocation - it's a driver-wide thing and it will live until - * the unload, but we don't allocate it until it's needed + * lazy allocate the driver-wide dummy buffer. (Note that we + * never have more than one MACE in the system anyway) */ if (dummy_buf == NULL) { dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); if (dummy_buf == NULL) { printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n"); - return; + return -ENOMEM; } } + if (macio_request_resources(mdev, "mace")) { + printk(KERN_ERR "MACE: can't request IO resources !\n"); + return -EBUSY; + } + dev = alloc_etherdev(PRIV_BYTES); - if (!dev) - return; + if (!dev) { + printk(KERN_ERR "MACE: can't allocate ethernet device !\n"); + rc = -ENOMEM; + goto err_release; + } SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &mdev->ofdev.dev); mp = dev->priv; - mp->of_node = mace; - - if (!request_OF_resource(mace, 0, " (mace)")) { - printk(KERN_ERR "MACE: can't request IO resource !\n"); - goto out1; - } - if (!request_OF_resource(mace, 1, " (mace tx dma)")) { - printk(KERN_ERR "MACE: can't request TX DMA resource !\n"); - goto out2; - } - - if (!request_OF_resource(mace, 2, " (mace tx dma)")) { - printk(KERN_ERR "MACE: can't request RX DMA resource !\n"); - goto out3; - } - - dev->base_addr = mace->addrs[0].address; - mp->mace = (volatile struct mace *) - ioremap(mace->addrs[0].address, 0x1000); - dev->irq = mace->intrs[0].line; + mp->mdev = mdev; + macio_set_drvdata(mdev, dev); + + dev->base_addr = macio_resource_start(mdev, 0); + mp->mace = (volatile struct mace *)ioremap(dev->base_addr, 0x1000); + if (mp->mace == NULL) { + printk(KERN_ERR "MACE: can't map IO resources !\n"); + rc = -ENOMEM; + goto err_free; + } + dev->irq = macio_irq(mdev, 0); printk(KERN_INFO "%s: MACE at", dev->name); rev = addr[0] == 0 && addr[1] == 0xA0; @@ -194,12 +185,24 @@ mp = (struct mace_data *) dev->priv; mp->maccc = ENXMT | ENRCV; + mp->tx_dma = (volatile struct dbdma_regs *) - ioremap(mace->addrs[1].address, 0x1000); - mp->tx_dma_intr = mace->intrs[1].line; + ioremap(macio_resource_start(mdev, 1), 0x1000); + if (mp->tx_dma == NULL) { + printk(KERN_ERR "MACE: can't map TX DMA resources !\n"); + rc = -ENOMEM; + goto err_unmap_io; + } + mp->tx_dma_intr = macio_irq(mdev, 1); + mp->rx_dma = (volatile struct dbdma_regs *) - ioremap(mace->addrs[2].address, 0x1000); - mp->rx_dma_intr = mace->intrs[2].line; + ioremap(macio_resource_start(mdev, 2), 0x1000); + if (mp->rx_dma == NULL) { + printk(KERN_ERR "MACE: can't map RX DMA resources !\n"); + rc = -ENOMEM; + goto err_unmap_tx_dma; + } + mp->rx_dma_intr = macio_irq(mdev, 2);; mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1); mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1; @@ -233,43 +236,81 @@ dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; + /* + * Most of what is below could be moved to mace_open() + */ mace_reset(dev); - if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { + rc = request_irq(dev->irq, mace_interrupt, 0, "MACE", dev); + if (rc) { printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); - goto out4; + goto err_unmap_rx_dma; } - if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", - dev)) { + rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev); + if (rc) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); - goto out5; + goto err_free_irq; } - if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", - dev)) { + rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev); + if (rc) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); - goto out6; + goto err_free_tx_irq; } - if (register_netdev(dev) != 0) - goto out7; - mp->next_mace = mace_devs; - mace_devs = dev; - return; - -out7: - free_irq(mp->rx_dma_intr, dev); -out6: - free_irq(mp->tx_dma_intr, dev); -out5: + rc = register_netdev(dev); + if (rc) { + printk(KERN_ERR "Cannot register net device, aborting.\n"); + goto err_free_rx_irq; + } + + return 0; + + err_free_rx_irq: + free_irq(macio_irq(mdev, 2), dev); + err_free_tx_irq: + free_irq(macio_irq(mdev, 1), dev); + err_free_irq: + free_irq(macio_irq(mdev, 0), dev); + err_unmap_rx_dma: + iounmap((void*)mp->rx_dma); + err_unmap_tx_dma: + iounmap((void*)mp->tx_dma); + err_unmap_io: + iounmap((void*)mp->mace); + err_free: + free_netdev(dev); + err_release: + macio_release_resources(mdev); + + return rc; +} + +static int __devexit mace_remove(struct macio_dev *mdev) +{ + struct net_device *dev = macio_get_drvdata(mdev); + struct mace_data *mp; + + BUG_ON(dev == NULL); + + macio_set_drvdata(mdev, NULL); + + mp = dev->priv; + + unregister_netdev(dev); + free_irq(dev->irq, dev); -out4: - release_OF_resource(mp->of_node, 2); -out3: - release_OF_resource(mp->of_node, 1); -out2: - release_OF_resource(mp->of_node, 0); -out1: + free_irq(mp->tx_dma_intr, dev); + free_irq(mp->rx_dma_intr, dev); + + iounmap((void*)mp->rx_dma); + iounmap((void*)mp->tx_dma); + iounmap((void*)mp->mace); + free_netdev(dev); + + macio_release_resources(mdev); + + return 0; } static void dbdma_reset(volatile struct dbdma_regs *dma) @@ -967,37 +1008,45 @@ return IRQ_HANDLED; } -MODULE_AUTHOR("Paul Mackerras"); -MODULE_DESCRIPTION("PowerMac MACE driver."); -MODULE_PARM(port_aaui, "i"); -MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)"); -MODULE_LICENSE("GPL"); +static struct of_match mace_match[] = +{ + { + .name = "mace", + .type = OF_ANY_MATCH, + .compatible = OF_ANY_MATCH + }, + {}, +}; -static void __exit mace_cleanup (void) +static struct macio_driver mace_driver = { - struct net_device *dev; - struct mace_data *mp; + .name = "mace", + .match_table = mace_match, + .probe = mace_probe, + .remove = mace_remove, +}; - while ((dev = mace_devs) != 0) { - mp = (struct mace_data *) mace_devs->priv; - mace_devs = mp->next_mace; - unregister_netdev(dev); - free_irq(dev->irq, dev); - free_irq(mp->tx_dma_intr, dev); - free_irq(mp->rx_dma_intr, dev); +static int __init mace_init(void) +{ + return macio_register_driver(&mace_driver); +} - release_OF_resource(mp->of_node, 0); - release_OF_resource(mp->of_node, 1); - release_OF_resource(mp->of_node, 2); +static void __exit mace_cleanup(void) +{ + macio_unregister_driver(&mace_driver); - free_netdev(dev); - } - if (dummy_buf != NULL) { + if (dummy_buf) { kfree(dummy_buf); dummy_buf = NULL; - } + } } -module_init(mace_probe); +MODULE_AUTHOR("Paul Mackerras"); +MODULE_DESCRIPTION("PowerMac MACE driver."); +MODULE_PARM(port_aaui, "i"); +MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)"); +MODULE_LICENSE("GPL"); + +module_init(mace_init); module_exit(mace_cleanup); diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- a/drivers/net/wireless/airport.c Sun Feb 15 23:14:38 2004 +++ b/drivers/net/wireless/airport.c Sun Feb 15 23:14:38 2004 @@ -40,7 +40,7 @@ #define AIRPORT_IO_LEN (0x1000) /* one page */ struct airport { - struct device_node *node; + struct macio_dev *mdev; void *vaddr; int irq_requested; int ndev_registered; @@ -51,7 +51,6 @@ { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); struct orinoco_private *priv = dev->priv; - struct airport *card = priv->card; unsigned long flags; int err; @@ -76,7 +75,7 @@ orinoco_unlock(priv, &flags); disable_irq(dev->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); return 0; } @@ -86,14 +85,14 @@ { struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); struct orinoco_private *priv = dev->priv; - struct airport *card = priv->card; unsigned long flags; int err; printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); - mdelay(200); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/5); enable_irq(dev->irq); @@ -142,15 +141,13 @@ iounmap(card->vaddr); card->vaddr = 0; - dev->base_addr = 0; + macio_release_resource(mdev, 0); - release_OF_resource(card->node, 0); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); - current->state = TASK_UNINTERRUPTIBLE; + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); - dev_set_drvdata(&mdev->ofdev.dev, NULL); + macio_set_drvdata(mdev, NULL); free_netdev(dev); return 0; @@ -173,11 +170,11 @@ * off. */ disable_irq(dev->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); - current->state = TASK_UNINTERRUPTIBLE; + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); - current->state = TASK_UNINTERRUPTIBLE; + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); enable_irq(dev->irq); @@ -194,10 +191,9 @@ struct net_device *dev; struct airport *card; unsigned long phys_addr; - struct device_node *of_node = mdev->ofdev.node; hermes_t *hw; - if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { + if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); return -ENODEV; } @@ -212,27 +208,26 @@ card = priv->card; hw = &priv->hw; - card->node = of_node; + card->mdev = mdev; - if (! request_OF_resource(of_node, 0, " (airport)")) { + if (macio_request_resource(mdev, 0, "airport")) { printk(KERN_ERR "airport: can't request IO resource !\n"); free_netdev(dev); - return -ENODEV; + return -EBUSY; } - dev->name[0] = '\0'; /* register_netdev will give us an ethX name */ SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - dev_set_drvdata(&mdev->ofdev.dev, dev); + macio_set_drvdata(mdev, dev); /* Setup interrupts & base address */ - dev->irq = of_node->intrs[0].line; - phys_addr = of_node->addrs[0].address; /* Physical address */ + dev->irq = macio_irq(mdev, 0); + phys_addr = macio_resource_start(mdev, 0); /* Physical address */ printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr); dev->base_addr = phys_addr; card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); - if (! card->vaddr) { + if (!card->vaddr) { printk("airport: ioremap() failed\n"); goto failed; } @@ -241,8 +236,8 @@ HERMES_MEM, HERMES_16BIT_REGSPACING); /* Power up card */ - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); - current->state = TASK_UNINTERRUPTIBLE; + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); /* Reset it before we get the interrupt */ diff -Nru a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c --- a/drivers/video/aty/aty128fb.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/aty/aty128fb.c Sun Feb 15 23:14:38 2004 @@ -13,6 +13,7 @@ * * Benjamin Herrenschmidt * - pmac-specific PM stuff + * - various fixes & cleanups * * Andreas Hundt * - FB_ACTIVATE fixes @@ -24,6 +25,10 @@ * Paul Mundt * - PCI hotplug * + * Jon Smirl + * - PCI ID update + * - replace ROM BIOS search + * * Based off of Geert's atyfb.c and vfb.c. * * TODO: @@ -43,6 +48,7 @@ #include #include +#include #include #include #include @@ -57,6 +63,7 @@ #include #include #include +#include #include #ifdef CONFIG_PPC_PMAC @@ -65,11 +72,6 @@ #include "../macmodes.h" #endif -#ifdef CONFIG_ADB_PMU -#include -#include -#endif - #ifdef CONFIG_PMAC_BACKLIGHT #include #endif @@ -136,8 +138,25 @@ /* Chip generations */ enum { rage_128, + rage_128_pci, rage_128_pro, - rage_M3 + rage_128_pro_pci, + rage_M3, + rage_M3_pci, + rage_M4, + rage_128_ultra, +}; + +/* Must match above enum */ +static const char *r128_family[] __devinitdata = { + "AGP", + "PCI", + "PRO AGP", + "PRO PCI", + "M3 AGP", + "M3 PCI", + "M4 AGP", + "Ultra AGP", }; /* @@ -146,35 +165,105 @@ static int aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void aty128_remove(struct pci_dev *pdev); +static int aty128_pci_suspend(struct pci_dev *pdev, u32 state); +static int aty128_pci_resume(struct pci_dev *pdev); /* supported Rage128 chipsets */ static struct pci_device_id aty128_pci_tbl[] = { - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_Rage128_PD, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U3, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U1, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra }, { 0, } }; @@ -185,6 +274,8 @@ .id_table = aty128_pci_tbl, .probe = aty128_probe, .remove = __devexit_p(aty128_remove), + .suspend = aty128_pci_suspend, + .resume = aty128_pci_resume, }; /* packed BIOS settings */ @@ -250,13 +341,6 @@ .accel = FB_ACCEL_ATI_RAGE128, }; -#ifdef MODULE -static char *mode __initdata = NULL; -#ifdef CONFIG_MTRR -static int nomtrr __initdata = 0; -#endif /* CONFIG_MTRR */ -#endif /* MODULE */ - static char *mode_option __initdata = NULL; #ifdef CONFIG_PPC_PMAC @@ -275,7 +359,7 @@ /* PLL constants */ struct aty128_constants { - u32 dotclock; + u32 ref_clk; u32 ppll_min; u32 ppll_max; u32 ref_divider; @@ -322,26 +406,20 @@ #endif int blitter_may_be_busy; int fifo_slots; /* free slots in FIFO (64 max) */ -#ifdef CONFIG_PMAC_PBOOK - unsigned char *save_framebuffer; + int pm_reg; int crt_on, lcd_on; struct pci_dev *pdev; struct fb_info *next; -#endif + int asleep; + int lock_blank; + u8 red[32]; /* see aty128fb_setcolreg */ u8 green[64]; u8 blue[32]; u32 pseudo_palette[16]; /* used for TRUECOLOR */ }; -#ifdef CONFIG_PMAC_PBOOK -int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when); -static struct pmu_sleep_notifier aty128_sleep_notifier = { - aty128_sleep_notify, SLEEP_LEVEL_VIDEO, -}; -static struct fb_info *aty128_fb = NULL; -#endif #define round_div(n, d) ((n+(d/2))/d) @@ -349,7 +427,6 @@ * Interface used by the world */ int aty128fb_init(void); -int aty128fb_setup(char *options); static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); @@ -371,10 +448,10 @@ const struct aty128fb_par *par); static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par); -#if !defined(CONFIG_PPC) && !defined(__sparc__) +#if 0 static void __init aty128_get_pllinfo(struct aty128fb_par *par, void *bios); -static void __init *aty128_map_ROM(struct pci_dev *pdev); +static void __init *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom); #endif static void aty128_timings(struct aty128fb_par *par); @@ -386,6 +463,15 @@ static void wait_for_idle(struct aty128fb_par *par); static u32 depth_to_dst(u32 depth); +#define BIOS_IN8(v) (readb(bios + (v))) +#define BIOS_IN16(v) (readb(bios + (v)) | \ + (readb(bios + (v) + 1) << 8)) +#define BIOS_IN32(v) (readb(bios + (v)) | \ + (readb(bios + (v) + 1) << 8) | \ + (readb(bios + (v) + 2) << 16) | \ + (readb(bios + (v) + 3) << 24)) + + static struct fb_ops aty128fb_ops = { .owner = THIS_MODULE, .fb_check_var = aty128fb_check_var, @@ -395,15 +481,9 @@ .fb_blank = aty128fb_blank, .fb_ioctl = aty128fb_ioctl, .fb_sync = aty128fb_sync, -#if 0 - .fb_fillrect = aty128fb_fillrect, - .fb_copyarea = aty128fb_copyarea, - .fb_imageblit = aty128fb_imageblit, -#else .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, -#endif .fb_cursor = soft_cursor, }; @@ -422,40 +502,26 @@ * - endian conversions may possibly be avoided by * using the other register aperture. TODO. */ -static inline u32 -_aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par) +static inline u32 _aty_ld_le32(volatile unsigned int regindex, + const struct aty128fb_par *par) { - u32 val; - -#if defined(__powerpc__) - asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(par->regbase)); -#else - val = readl (par->regbase + regindex); -#endif - - return val; + return readl (par->regbase + regindex); } -static inline void -_aty_st_le32(volatile unsigned int regindex, u32 val, - const struct aty128fb_par *par) +static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, + const struct aty128fb_par *par) { -#if defined(__powerpc__) - asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex), - "r"(par->regbase) : "memory"); -#else writel (val, par->regbase + regindex); -#endif } -static inline u8 -_aty_ld_8(unsigned int regindex, const struct aty128fb_par *par) +static inline u8 _aty_ld_8(unsigned int regindex, + const struct aty128fb_par *par) { return readb (par->regbase + regindex); } -static inline void -_aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par) +static inline void _aty_st_8(unsigned int regindex, u8 val, + const struct aty128fb_par *par) { writeb (val, par->regbase + regindex); } @@ -473,17 +539,15 @@ #define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, par) -static u32 -_aty_ld_pll(unsigned int pll_index, - const struct aty128fb_par *par) +static u32 _aty_ld_pll(unsigned int pll_index, + const struct aty128fb_par *par) { aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); return aty_ld_le32(CLOCK_CNTL_DATA); } -static void -_aty_st_pll(unsigned int pll_index, u32 val, +static void _aty_st_pll(unsigned int pll_index, u32 val, const struct aty128fb_par *par) { aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN); @@ -492,15 +556,13 @@ /* return true when the PLL has completed an atomic update */ -static int -aty_pll_readupdate(const struct aty128fb_par *par) +static int aty_pll_readupdate(const struct aty128fb_par *par) { return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); } -static void -aty_pll_wait_readupdate(const struct aty128fb_par *par) +static void aty_pll_wait_readupdate(const struct aty128fb_par *par) { unsigned long timeout = jiffies + HZ/100; // should be more than enough int reset = 1; @@ -517,8 +579,7 @@ /* tell PLL to update */ -static void -aty_pll_writeupdate(const struct aty128fb_par *par) +static void aty_pll_writeupdate(const struct aty128fb_par *par) { aty_pll_wait_readupdate(par); @@ -528,8 +589,7 @@ /* write to the scratch register to test r/w functionality */ -static int __init -register_test(const struct aty128fb_par *par) +static int __init register_test(const struct aty128fb_par *par) { u32 val; int flag = 0; @@ -552,8 +612,7 @@ /* * Accelerator engine functions */ -static void -do_wait_for_fifo(u16 entries, struct aty128fb_par *par) +static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par) { int i; @@ -568,8 +627,7 @@ } -static void -wait_for_idle(struct aty128fb_par *par) +static void wait_for_idle(struct aty128fb_par *par) { int i; @@ -588,8 +646,7 @@ } -static void -wait_for_fifo(u16 entries, struct aty128fb_par *par) +static void wait_for_fifo(u16 entries, struct aty128fb_par *par) { if (par->fifo_slots < entries) do_wait_for_fifo(64, par); @@ -597,8 +654,7 @@ } -static void -aty128_flush_pixel_cache(const struct aty128fb_par *par) +static void aty128_flush_pixel_cache(const struct aty128fb_par *par) { int i; u32 tmp; @@ -614,8 +670,7 @@ } -static void -aty128_reset_engine(const struct aty128fb_par *par) +static void aty128_reset_engine(const struct aty128fb_par *par) { u32 gen_reset_cntl, clock_cntl_index, mclk_cntl; @@ -643,8 +698,7 @@ } -static void -aty128_init_engine(struct aty128fb_par *par) +static void aty128_init_engine(struct aty128fb_par *par) { u32 pitch_value; @@ -712,8 +766,7 @@ /* convert depth values to their register representation */ -static u32 -depth_to_dst(u32 depth) +static u32 depth_to_dst(u32 depth) { if (depth <= 8) return DST_8BPP; @@ -729,15 +782,247 @@ return -EINVAL; } +/* + * PLL informations retreival + */ + + +#ifndef __sparc__ +static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom) +{ + struct resource *r = &dev->resource[PCI_ROM_RESOURCE]; + + iounmap(rom); + + /* Release the ROM resource if we used it in the first place */ + if (r->parent && r->flags & PCI_ROM_ADDRESS_ENABLE) { + release_resource(r); + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + r->end -= r->start; + r->start = 0; + } + /* This will disable and set address to unassigned */ + pci_write_config_dword(dev, dev->rom_base_reg, 0); +} + + +static void * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) +{ + struct resource *r; + u16 dptr; + u8 rom_type; + void *bios; + + /* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */ + unsigned int temp; + temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG); + temp &= 0x00ffffffu; + temp |= 0x04 << 24; + aty_st_le32(RAGE128_MPP_TB_CONFIG, temp); + temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG); + + /* no need to search for the ROM, just ask the card where it is. */ + r = &dev->resource[PCI_ROM_RESOURCE]; + + /* assign the ROM an address if it doesn't have one */ + if (r->parent == NULL) + pci_assign_resource(dev, PCI_ROM_RESOURCE); + + /* enable if needed */ + if (!(r->flags & PCI_ROM_ADDRESS_ENABLE)) { + pci_write_config_dword(dev, dev->rom_base_reg, + r->start | PCI_ROM_ADDRESS_ENABLE); + r->flags |= PCI_ROM_ADDRESS_ENABLE; + } + + bios = ioremap(r->start, r->end - r->start + 1); + if (!bios) { + printk(KERN_ERR "aty128fb: ROM failed to map\n"); + return NULL; + } + + /* Very simple test to make sure it appeared */ + if (BIOS_IN16(0) != 0xaa55) { + printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n", + BIOS_IN16(0)); + goto failed; + } + + /* Look for the PCI data to check the ROM type */ + dptr = BIOS_IN16(0x18); + + /* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM + * for now, until I've verified this works everywhere. The goal here is more + * to phase out Open Firmware images. + * + * Currently, we only look at the first PCI data, we could iteratre and deal with + * them all, and we should use fb_bios_start relative to start of image and not + * relative start of ROM, but so far, I never found a dual-image ATI card + * + * typedef struct { + * u32 signature; + 0x00 + * u16 vendor; + 0x04 + * u16 device; + 0x06 + * u16 reserved_1; + 0x08 + * u16 dlen; + 0x0a + * u8 drevision; + 0x0c + * u8 class_hi; + 0x0d + * u16 class_lo; + 0x0e + * u16 ilen; + 0x10 + * u16 irevision; + 0x12 + * u8 type; + 0x14 + * u8 indicator; + 0x15 + * u16 reserved_2; + 0x16 + * } pci_data_t; + */ + if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { + printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n", + BIOS_IN32(dptr)); + goto anyway; + } + rom_type = BIOS_IN8(dptr + 0x14); + switch(rom_type) { + case 0: + printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n"); + break; + case 1: + printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n"); + goto failed; + case 2: + printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n"); + goto failed; + default: + printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type); + goto failed; + } + anyway: + return bios; + + failed: + aty128_unmap_ROM(dev, bios); + return NULL; +} + +static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char *bios) +{ + unsigned int bios_hdr; + unsigned int bios_pll; + + bios_hdr = BIOS_IN16(0x48); + bios_pll = BIOS_IN16(bios_hdr + 0x30); + + par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16); + par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12); + par->constants.xclk = BIOS_IN16(bios_pll + 0x08); + par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10); + par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e); + + DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n", + par->constants.ppll_max, par->constants.ppll_min, + par->constants.xclk, par->constants.ref_divider, + par->constants.ref_clk); + +} + +#ifdef __i386__ +static void * __devinit aty128_find_mem_vbios(struct aty128fb_par *par) +{ + /* I simplified this code as we used to miss the signatures in + * a lot of case. It's now closer to XFree, we just don't check + * for signatures at all... Something better will have to be done + * if we end up having conflicts + */ + u32 segstart; + unsigned char *rom_base = NULL; + + for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { + rom_base = (char *)ioremap(segstart, 0x10000); + if (rom_base == NULL) + return NULL; + if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) + break; + iounmap(rom_base); + rom_base = NULL; + } + return rom_base; +} +#endif /* __i386__ */ +#endif /* ndef(__sparc__) */ + +/* fill in known card constants if pll_block is not available */ +static void __init aty128_timings(struct aty128fb_par *par) +{ +#ifdef CONFIG_PPC_OF + /* instead of a table lookup, assume OF has properly + * setup the PLL registers and use their values + * to set the XCLK values and reference divider values */ + + u32 x_mpll_ref_fb_div; + u32 xclk_cntl; + u32 Nx, M; + unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 }; +#endif + + if (!par->constants.ref_clk) + par->constants.ref_clk = 2950; + +#ifdef CONFIG_PPC_OF + x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); + xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; + Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; + M = x_mpll_ref_fb_div & 0x0000ff; + + par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk), + (M * PostDivSet[xclk_cntl])); + + par->constants.ref_divider = + aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; +#endif + + if (!par->constants.ref_divider) { + par->constants.ref_divider = 0x3b; + + aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); + aty_pll_writeupdate(par); + } + aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider); + aty_pll_writeupdate(par); + + /* from documentation */ + if (!par->constants.ppll_min) + par->constants.ppll_min = 12500; + if (!par->constants.ppll_max) + par->constants.ppll_max = 25000; /* 23000 on some cards? */ + if (!par->constants.xclk) + par->constants.xclk = 0x1d4d; /* same as mclk */ + + par->constants.fifo_width = 128; + par->constants.fifo_depth = 32; + + switch (aty_ld_le32(MEM_CNTL) & 0x3) { + case 0: + par->mem = &sdr_128; + break; + case 1: + par->mem = &sdr_sgram; + break; + case 2: + par->mem = &ddr_sgram; + break; + default: + par->mem = &sdr_sgram; + } +} + + /* - * CRTC programming - */ + * CRTC programming + */ /* Program the CRTC registers */ -static void -aty128_set_crtc(const struct aty128_crtc *crtc, - const struct aty128fb_par *par) +static void aty128_set_crtc(const struct aty128_crtc *crtc, + const struct aty128fb_par *par) { aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl); aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total); @@ -752,10 +1037,9 @@ } -static int -aty128_var_to_crtc(const struct fb_var_screeninfo *var, - struct aty128_crtc *crtc, - const struct aty128fb_par *par) +static int aty128_var_to_crtc(const struct fb_var_screeninfo *var, + struct aty128_crtc *crtc, + const struct aty128fb_par *par) { u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst; u32 left, right, upper, lower, hslen, vslen, sync, vmode; @@ -881,8 +1165,7 @@ } -static int -aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var) +static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var) { /* fill in pixel info */ @@ -945,9 +1228,8 @@ } -static int -aty128_crtc_to_var(const struct aty128_crtc *crtc, - struct fb_var_screeninfo *var) +static int aty128_crtc_to_var(const struct aty128_crtc *crtc, + struct fb_var_screeninfo *var) { u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; @@ -1003,8 +1285,7 @@ } #ifdef CONFIG_PMAC_PBOOK -static void -aty128_set_crt_enable(struct aty128fb_par *par, int on) +static void aty128_set_crt_enable(struct aty128fb_par *par, int on) { if (on) { aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON); @@ -1013,8 +1294,7 @@ aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON); } -static void -aty128_set_lcd_enable(struct aty128fb_par *par, int on) +static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) { u32 reg; @@ -1039,10 +1319,9 @@ aty_st_le32(LVDS_GEN_CNTL, reg); } } -#endif +#endif /* CONFIG_PMAC_PBOOK */ -static void -aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) +static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) { u32 div3; @@ -1081,9 +1360,8 @@ } -static int -aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, - const struct aty128fb_par *par) +static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, + const struct aty128fb_par *par) { const struct aty128_constants c = par->constants; unsigned char post_dividers[] = {1,2,4,8,3,6,12}; @@ -1109,7 +1387,7 @@ /* calculate feedback divider */ n = c.ref_divider * output_freq; - d = c.dotclock; + d = c.ref_clk; pll->post_divider = post_dividers[i]; pll->feedback_divider = round_div(n, d); @@ -1124,8 +1402,7 @@ } -static int -aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var) +static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var) { var->pixclock = 100000000 / pll->vclk; @@ -1133,20 +1410,18 @@ } -static void -aty128_set_fifo(const struct aty128_ddafifo *dsp, - const struct aty128fb_par *par) +static void aty128_set_fifo(const struct aty128_ddafifo *dsp, + const struct aty128fb_par *par) { aty_st_le32(DDA_CONFIG, dsp->dda_config); aty_st_le32(DDA_ON_OFF, dsp->dda_on_off); } -static int -aty128_ddafifo(struct aty128_ddafifo *dsp, - const struct aty128_pll *pll, - u32 depth, - const struct aty128fb_par *par) +static int aty128_ddafifo(struct aty128_ddafifo *dsp, + const struct aty128_pll *pll, + u32 depth, + const struct aty128fb_par *par) { const struct aty128_meminfo *m = par->mem; u32 xclk = par->constants.xclk; @@ -1203,8 +1478,7 @@ /* * This actually sets the video mode. */ -static int -aty128fb_set_par(struct fb_info *info) +static int aty128fb_set_par(struct fb_info *info) { struct aty128fb_par *par = info->par; u32 config; @@ -1276,8 +1550,7 @@ * encode/decode the User Defined Part of the Display */ -static int -aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par) +static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par) { int err; struct aty128_crtc crtc; @@ -1302,9 +1575,8 @@ } -static int -aty128_encode_var(struct fb_var_screeninfo *var, - const struct aty128fb_par *par) +static int aty128_encode_var(struct fb_var_screeninfo *var, + const struct aty128fb_par *par) { int err; @@ -1325,8 +1597,7 @@ } -static int -aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct aty128fb_par par; int err; @@ -1342,8 +1613,7 @@ /* * Pan or Wrap the Display */ -static int -aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) +static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) { struct aty128fb_par *par = fb->par; u32 xoffset, yoffset; @@ -1376,9 +1646,8 @@ /* * Helper function to store a single palette register */ -static void -aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, - struct aty128fb_par *par) +static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, + struct aty128fb_par *par) { if (par->chip_gen == rage_M3) { #if 0 @@ -1400,8 +1669,7 @@ aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); } -static int -aty128fb_sync(struct fb_info *info) +static int aty128fb_sync(struct fb_info *info) { struct aty128fb_par *par = info->par; @@ -1410,8 +1678,7 @@ return 0; } -int __init -aty128fb_setup(char *options) +int __init aty128fb_setup(char *options) { char *this_opt; @@ -1470,13 +1737,12 @@ * Initialisation */ -static int __init -aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) { struct fb_info *info = pci_get_drvdata(pdev); struct aty128fb_par *par = info->par; struct fb_var_screeninfo var; - char video_card[25]; + char video_card[DEVICE_NAME_SIZE]; u8 chip_rev; u32 dac; @@ -1486,43 +1752,13 @@ /* Get the chip revision */ chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; - switch (pdev->device) { - case PCI_DEVICE_ID_ATI_RAGE128_RE: - strcpy(video_card, "Rage128 RE (PCI)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_RF: - strcpy(video_card, "Rage128 RF (AGP)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_RK: - strcpy(video_card, "Rage128 RK (PCI)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_RL: - strcpy(video_card, "Rage128 RL (AGP)"); - break; - case PCI_DEVICE_ID_ATI_Rage128_PD: - strcpy(video_card, "Rage128 Pro PD (PCI)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_PF: - strcpy(video_card, "Rage128 Pro PF (AGP)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_PR: - strcpy(video_card, "Rage128 Pro PR (PCI)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_U3: - strcpy(video_card, "Rage128 Pro TR (AGP)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_U1: - strcpy(video_card, "Rage128 Pro TF (AGP)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_LE: - strcpy(video_card, "Rage Mobility M3 (PCI)"); - break; - case PCI_DEVICE_ID_ATI_RAGE128_LF: - strcpy(video_card, "Rage Mobility M3 (AGP)"); - break; - default: - return -ENODEV; - } + strcpy(video_card, "Rage128 XX "); + video_card[8] = ent->device >> 8; + video_card[9] = ent->device & 0xFF; + + /* range check to make sure */ + if (ent->driver_data < (sizeof(r128_family)/sizeof(char *))) + strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); @@ -1575,8 +1811,12 @@ if (machine_is_compatible("PowerBook3,2")) default_vmode = VMODE_1152_768_60; - if (default_cmode < CMODE_8 || default_cmode > CMODE_32) - default_cmode = CMODE_8; + if (default_cmode > 16) + default_cmode = CMODE_32; + else if (default_cmode > 8) + default_cmode = CMODE_16; + else + default_cmode = CMODE_8; if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; @@ -1584,9 +1824,10 @@ } else #endif /* CONFIG_PPC_PMAC */ { - if (fb_find_mode(&var, info, mode_option, NULL, 0, - &defaultmode, 8) == 0) - var = default_var; + if (mode_option) + if (fb_find_mode(&var, info, mode_option, NULL, + 0, &defaultmode, 8) == 0) + var = default_var; } var.accel_flags &= ~FB_ACCELF_TEXT; @@ -1623,16 +1864,12 @@ if (par->chip_gen == rage_M3) register_backlight_controller(&aty128_backlight_controller, par, "ati"); #endif /* CONFIG_PMAC_BACKLIGHT */ -#ifdef CONFIG_PMAC_PBOOK + par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (aty128_fb == NULL) { - /* XXX can only put one chip to sleep */ - aty128_fb = info; - } else - printk(KERN_WARNING "aty128fb: can only sleep one Rage 128\n"); par->pdev = pdev; -#endif - + par->asleep = 0; + par->lock_blank = 0; + printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", info->node, info->fix.id, video_card); @@ -1641,14 +1878,13 @@ #ifdef CONFIG_PCI /* register a card ++ajoshi */ -static int __init -aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned long fb_addr, reg_addr; struct aty128fb_par *par; struct fb_info *info; - int err, size; -#if !defined(CONFIG_PPC) && !defined(__sparc__) + int err; +#ifndef __sparc__ void *bios = NULL; #endif @@ -1675,17 +1911,14 @@ } /* We have the resources. Now virtualize them */ - size = sizeof(struct fb_info) + sizeof(struct aty128fb_par); - if (!(info = kmalloc(size, GFP_ATOMIC))) { + info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev); + if (info == NULL) { printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); goto err_free_mmio; } - memset(info, 0, size); + par = info->par; - par = (struct aty128fb_par *)(info + 1); info->pseudo_palette = par->pseudo_palette; - - info->par = par; info->fix = aty128fb_fix; /* Virtualize mmio region */ @@ -1715,16 +1948,21 @@ goto err_out; } -#if !defined(CONFIG_PPC) && !defined(__sparc__) - if (!(bios = aty128_map_ROM(pdev))) +#ifndef __sparc__ + bios = aty128_map_ROM(par, pdev); +#ifdef __i386__ + if (bios == NULL) + bios = aty128_find_mem_vbios(par, pdev); +#endif + if (bios == NULL) printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n"); else { - printk(KERN_INFO "aty128fb: Rage128 BIOS located at %lx\n", - pdev->resource[PCI_ROM_RESOURCE].start); + printk(KERN_INFO "aty128fb: Rage128 BIOS located\n"); aty128_get_pllinfo(par, bios); aty128_unmap_ROM(pdev, bios); } -#endif +#endif /* __sparc__ */ + aty128_timings(par); pci_set_drvdata(pdev, info); @@ -1747,7 +1985,7 @@ err_unmap_out: iounmap(par->regbase); err_free_info: - kfree(info); + framebuffer_release(info); err_free_mmio: release_mem_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); @@ -1780,170 +2018,23 @@ pci_resource_len(pdev, 1)); release_mem_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); -#ifdef CONFIG_PMAC_PBOOK - if (info == aty128_fb) - aty128_fb = NULL; -#endif - kfree(info); + framebuffer_release(info); } #endif /* CONFIG_PCI */ -/* PPC and Sparc cannot read video ROM */ -#if !defined(CONFIG_PPC) && !defined(__sparc__) -static void * __init aty128_map_ROM(struct pci_dev *dev) -{ - // If this is a primary card, there is a shadow copy of the - // ROM somewhere in the first meg. We will just ignore the copy - // and use the ROM directly. - - // no need to search for the ROM, just ask the card where it is. - struct resource *r = &dev->resource[PCI_ROM_RESOURCE]; - unsigned char *addr; - - // assign the ROM an address if it doesn't have one - if (r->start == 0) - pci_assign_resource(dev, PCI_ROM_RESOURCE); - - // enable if needed - if (!(r->flags & PCI_ROM_ADDRESS_ENABLE)) - pci_write_config_dword(dev, dev->rom_base_reg, r->start | PCI_ROM_ADDRESS_ENABLE); - - addr = ioremap(r->start, r->end - r->start + 1); - - // Very simple test to make sure it appeared - if (addr && (*addr != 0x55)) { - printk("aty128fb: Invalid ROM signature %x\n", *addr); - iounmap(addr); - return NULL; - } - return (void *)addr; -} - -static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom) -{ - // leave it disabled and unassigned - struct resource *r = &dev->resource[PCI_ROM_RESOURCE]; - - iounmap(rom); - - r->flags &= !PCI_ROM_ADDRESS_ENABLE; - r->end -= r->start; - r->start = 0; - pci_write_config_dword(dev, dev->rom_base_reg, 0); -} - -static void __init -aty128_get_pllinfo(struct aty128fb_par *par, void *bios) -{ - void *bios_header; - void *header_ptr; - u16 bios_header_offset, pll_info_offset; - PLL_BLOCK pll; - - bios_header = (char *)bios + 0x48L; - header_ptr = bios_header; - - bios_header_offset = readw(header_ptr); - bios_header = (char *)bios + bios_header_offset; - bios_header += 0x30; - - header_ptr = bios_header; - pll_info_offset = readw(header_ptr); - header_ptr = (char *)bios + pll_info_offset; - - memcpy_fromio(&pll, header_ptr, 50); - - par->constants.ppll_max = pll.PCLK_max_freq; - par->constants.ppll_min = pll.PCLK_min_freq; - par->constants.xclk = (u32)pll.XCLK; - par->constants.ref_divider = (u32)pll.PCLK_ref_divider; - par->constants.dotclock = (u32)pll.PCLK_ref_freq; - - DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n", - par->constants.ppll_max, par->constants.ppll_min, - par->constants.xclk, par->constants.ref_divider, - par->constants.dotclock); - -} -#endif /* !CONFIG_PPC */ - - -/* fill in known card constants if pll_block is not available */ -static void __init -aty128_timings(struct aty128fb_par *par) -{ -#ifdef CONFIG_PPC_OF - /* instead of a table lookup, assume OF has properly - * setup the PLL registers and use their values - * to set the XCLK values and reference divider values */ - - u32 x_mpll_ref_fb_div; - u32 xclk_cntl; - u32 Nx, M; - unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 }; -#endif - - if (!par->constants.dotclock) - par->constants.dotclock = 2950; - -#ifdef CONFIG_PPC_OF - x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); - xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; - Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; - M = x_mpll_ref_fb_div & 0x0000ff; - - par->constants.xclk = round_div((2 * Nx * par->constants.dotclock), - (M * PostDivSet[xclk_cntl])); - - par->constants.ref_divider = - aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; -#endif - - if (!par->constants.ref_divider) { - par->constants.ref_divider = 0x3b; - - aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); - aty_pll_writeupdate(par); - } - aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider); - aty_pll_writeupdate(par); - - /* from documentation */ - if (!par->constants.ppll_min) - par->constants.ppll_min = 12500; - if (!par->constants.ppll_max) - par->constants.ppll_max = 25000; /* 23000 on some cards? */ - if (!par->constants.xclk) - par->constants.xclk = 0x1d4d; /* same as mclk */ - - par->constants.fifo_width = 128; - par->constants.fifo_depth = 32; - - switch (aty_ld_le32(MEM_CNTL) & 0x3) { - case 0: - par->mem = &sdr_128; - break; - case 1: - par->mem = &sdr_sgram; - break; - case 2: - par->mem = &ddr_sgram; - break; - default: - par->mem = &sdr_sgram; - } -} /* * Blank the display. */ -static int -aty128fb_blank(int blank, struct fb_info *fb) +static int aty128fb_blank(int blank, struct fb_info *fb) { struct aty128fb_par *par = fb->par; u8 state = 0; + if (par->lock_blank || par->asleep) + return 0; + #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) set_backlight_enable(0); @@ -1976,9 +2067,8 @@ * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */ -static int -aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { struct aty128fb_par *par = info->par; @@ -2041,9 +2131,9 @@ #define ATY_MIRROR_CRT_ON 0x00000002 /* out param: u32* backlight value: 0 to 15 */ -#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32*) +#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32) /* in param: u32* backlight value: 0 to 15 */ -#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32*) +#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32) static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, struct fb_info *info) @@ -2091,8 +2181,7 @@ /* That one prevents proper CRT output with LCD off */ #undef BACKLIGHT_DAC_OFF -static int -aty128_set_backlight_enable(int on, int level, void *data) +static int aty128_set_backlight_enable(int on, int level, void *data) { struct aty128fb_par *par = data; unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); @@ -2139,8 +2228,7 @@ return 0; } -static int -aty128_set_backlight_level(int level, void* data) +static int aty128_set_backlight_level(int level, void* data) { return aty128_set_backlight_enable(1, level, data); } @@ -2151,10 +2239,9 @@ * Accelerated functions */ -static inline void -aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, - u_int width, u_int height, - struct fb_info_aty128 *par) +static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, + u_int width, u_int height, + struct fb_info_aty128 *par) { u32 save_dp_datatype, save_dp_cntl, dstval; @@ -2196,8 +2283,7 @@ * Text mode accelerated functions */ -static void -fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, +static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { sx *= fontwidth(p); @@ -2212,9 +2298,7 @@ } #endif /* 0 */ -#ifdef CONFIG_PMAC_PBOOK -static void -aty128_set_suspend(struct aty128fb_par *par, int suspend) +static void aty128_set_suspend(struct aty128fb_par *par, int suspend) { u32 pmgt; u16 pwr_command; @@ -2257,95 +2341,122 @@ } } -/* - * Save the contents of the frame buffer when we go to sleep, - * and restore it when we wake up again. - */ -int -aty128_sleep_notify(struct pmu_sleep_notifier *self, int when) +static int aty128_pci_suspend(struct pci_dev *pdev, u32 state) { - int nb; - struct fb_info *info = aty128_fb; - struct aty128fb_par *par; + struct fb_info *info = pci_get_drvdata(pdev); + struct aty128fb_par *par = info->par; - if (info == NULL) - return PBOOK_SLEEP_OK; - par = info->par; - nb = info->var.yres * info->fix.line_length; + /* We don't do anything but D2, for now we return 0, but + * we may want to change that. How do we know if the BIOS + * can properly take care of D3 ? Also, with swsusp, we + * know we'll be rebooted, ... + */ +#ifdef CONFIG_PPC_PMAC + /* HACK ALERT ! Once I find a proper way to say to each driver + * individually what will happen with it's PCI slot, I'll change + * that. On laptops, the AGP slot is just unclocked, so D2 is + * expected, while on desktops, the card is powered off + */ + if (state >= 3) + state = 2; +#endif /* CONFIG_PPC_PMAC */ + + if (state != 2 || state == pdev->dev.power_state) + return 0; - switch (when) { - case PBOOK_SLEEP_REQUEST: - par->save_framebuffer = vmalloc(nb); - if (par->save_framebuffer == NULL) - return PBOOK_SLEEP_REFUSE; - break; - case PBOOK_SLEEP_REJECT: - if (par->save_framebuffer) { - vfree(par->save_framebuffer); - par->save_framebuffer = 0; - } - break; - case PBOOK_SLEEP_NOW: - wait_for_idle(par); - aty128_reset_engine(par); - wait_for_idle(par); + printk(KERN_DEBUG "aty128fb: suspending...\n"); + + acquire_console_sem(); + + fb_set_suspend(info, 1); + + /* Make sure engine is reset */ + wait_for_idle(par); + aty128_reset_engine(par); + wait_for_idle(par); + + /* Blank display and LCD */ + aty128fb_blank(VESA_POWERDOWN, info); - /* Backup fb content */ - if (par->save_framebuffer) - memcpy_fromio(par->save_framebuffer, - info->screen_base, nb); - - /* Blank display and LCD */ - aty128fb_blank(VESA_POWERDOWN, info); - - /* Sleep the chip */ + /* Sleep */ + par->asleep = 1; + par->lock_blank = 1; + + /* We need a way to make sure the fbdev layer will _not_ touch the + * framebuffer before we put the chip to suspend state. On 2.4, I + * used dummy fb ops, 2.5 need proper support for this at the + * fbdev level + */ + if (state == 2) aty128_set_suspend(par, 1); - break; - case PBOOK_WAKE: - /* Wake the chip */ + release_console_sem(); + + pdev->dev.power_state = state; + + return 0; +} + +static int aty128_pci_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct aty128fb_par *par = info->par; + + if (pdev->dev.power_state == 0) + return 0; + + acquire_console_sem(); + + /* Wakeup chip */ + if (pdev->dev.power_state == 2) aty128_set_suspend(par, 0); - - aty128_reset_engine(par); - wait_for_idle(par); + par->asleep = 0; - /* Restore fb content */ - if (par->save_framebuffer) { - memcpy_toio(info->screen_base, - par->save_framebuffer, nb); - vfree(par->save_framebuffer); - par->save_framebuffer = 0; - } - aty128fb_blank(0, info); - break; - } - return PBOOK_SLEEP_OK; + /* Restore display & engine */ + aty128_reset_engine(par); + wait_for_idle(par); + aty128fb_set_par(info); + fb_pan_display(info, &info->var); + fb_set_cmap(&info->cmap, 1, info); + + /* Refresh */ + fb_set_suspend(info, 0); + + /* Unblank */ + par->lock_blank = 0; + aty128fb_blank(0, info); + + release_console_sem(); + + pdev->dev.power_state = 0; + + printk(KERN_DEBUG "aty128fb: resumed !\n"); + + return 0; } -#endif /* CONFIG_PMAC_PBOOK */ int __init aty128fb_init(void) { -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&aty128_sleep_notifier); -#endif return pci_module_init(&aty128fb_driver); } static void __exit aty128fb_exit(void) { -#ifdef CONFIG_PMAC_PBOOK - pmu_unregister_sleep_notifier(&aty128_sleep_notifier); -#endif pci_unregister_driver(&aty128fb_driver); } +#ifdef MODULE +module_init(aty128fb_init); +module_exit(aty128fb_exit); + MODULE_AUTHOR("(c)1999-2003 Brad Douglas "); MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); MODULE_LICENSE("GPL"); -MODULE_PARM(mode, "s"); +module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode, "Specify resolution as \"x[-][@]\" "); #ifdef CONFIG_MTRR -MODULE_PARM(nomtrr, "i"); -MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); +module_param_named(nomtrr, mtrr, invbool, 0); +MODULE_PARM_DESC(mtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)"); +#endif #endif diff -Nru a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c --- a/drivers/video/aty/radeon_accel.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/aty/radeon_accel.c Sun Feb 15 23:14:38 2004 @@ -28,7 +28,7 @@ struct fb_fillrect modded; int vxres, vyres; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return; if (radeon_accel_disabled()) { cfb_fillrect(info, region); @@ -81,7 +81,7 @@ modded.width = area->width; modded.height = area->height; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return; if (radeon_accel_disabled()) { cfb_copyarea(info, area); @@ -108,7 +108,7 @@ { struct radeonfb_info *rinfo = info->par; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return; radeon_engine_idle(); @@ -119,7 +119,7 @@ { struct radeonfb_info *rinfo = info->par; - if (rinfo->asleep) + if (info->state != FBINFO_STATE_RUNNING) return 0; radeon_engine_idle(); diff -Nru a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c --- a/drivers/video/aty/radeon_base.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/aty/radeon_base.c Sun Feb 15 23:14:38 2004 @@ -566,8 +566,9 @@ break; } - do_div(vclk, 1000); - xtal = (xtal * denom) / num; + vclk *= denom; + do_div(vclk, 1000 * num); + xtal = vclk; if ((xtal > 26900) && (xtal < 27100)) xtal = 2700; @@ -1441,7 +1442,7 @@ nopllcalc = 1; newmode.ppll_div_3 = rinfo->panel_info.fbk_divider | (rinfo->panel_info.post_divider << 16); - newmode.ppll_ref_div = rinfo->pll.ref_div; + newmode.ppll_ref_div = rinfo->panel_info.ref_divider; } } dotClock = 1000000000 / pixClock; @@ -2331,7 +2332,7 @@ continue; if (!strncmp(this_opt, "noaccel", 7)) { - radeonfb_noaccel = 1; + noaccel = radeonfb_noaccel = 1; } else if (!strncmp(this_opt, "mirror", 6)) { mirror = 1; } else if (!strncmp(this_opt, "force_dfp", 9)) { diff -Nru a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c --- a/drivers/video/aty/radeon_monitor.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/aty/radeon_monitor.c Sun Feb 15 23:14:38 2004 @@ -759,7 +759,7 @@ rinfo->mon1_type = MT_CRT; goto pickup_default; } - printk(KERN_WARNING "radeonfb: Asssuming panel size %dx%d\n", + printk(KERN_WARNING "radeonfb: Assuming panel size %dx%d\n", rinfo->panel_info.xres, rinfo->panel_info.yres); modedb = rinfo->mon1_modedb; dbsize = rinfo->mon1_dbsize; diff -Nru a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c --- a/drivers/video/cfbcopyarea.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/cfbcopyarea.c Sun Feb 15 23:14:38 2004 @@ -346,6 +346,9 @@ int dst_idx = 0, src_idx = 0, rev_copy = 0; unsigned long *dst = NULL, *src = NULL; + if (p->state != FBINFO_STATE_RUNNING) + return; + /* We want rotation but lack hardware to do it for us. */ if (!p->fbops->fb_rotate && p->var.rotate) { } diff -Nru a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c --- a/drivers/video/cfbfillrect.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/cfbfillrect.c Sun Feb 15 23:14:38 2004 @@ -367,6 +367,9 @@ unsigned long *dst; int dst_idx, left; + if (p->state != FBINFO_STATE_RUNNING) + return; + /* We want rotation but lack hardware to do it for us. */ if (!p->fbops->fb_rotate && p->var.rotate) { } diff -Nru a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c --- a/drivers/video/cfbimgblt.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/cfbimgblt.c Sun Feb 15 23:14:38 2004 @@ -275,6 +275,9 @@ int x2, y2, vxres, vyres; u8 *dst1; + if (p->state != FBINFO_STATE_RUNNING) + return; + vxres = p->var.xres_virtual; vyres = p->var.yres_virtual; /* diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c --- a/drivers/video/console/fbcon.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/console/fbcon.c Sun Feb 15 23:14:38 2004 @@ -195,11 +195,13 @@ { struct fb_info *info = (struct fb_info *) private; - /* Test to see if the cursor is erased but still on */ - if (!info || (info->cursor.rop == ROP_COPY)) + if (!info || info->state != FBINFO_STATE_RUNNING || + info->cursor.rop == ROP_COPY) return; + acquire_console_sem(); info->cursor.enable ^= 1; info->fbops->fb_cursor(info, &info->cursor); + release_console_sem(); } #if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC) @@ -226,8 +228,7 @@ struct fb_info *info = (struct fb_info *) dev_addr; schedule_work(&info->queue); - cursor_timer.expires = jiffies + HZ / 5; - add_timer(&cursor_timer); + mod_timer(&cursor_timer, jiffies + HZ/5); } int __init fb_console_setup(char *this_opt) @@ -353,8 +354,6 @@ info->fbops->fb_imageblit(info, image); image->dx += cnt * vc->vc_font.width; count -= cnt; - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); } } @@ -393,8 +392,6 @@ info->fbops->fb_imageblit(info, image); image->dx += cnt * vc->vc_font.width; count -= cnt; - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); } } @@ -465,8 +462,6 @@ move_buf_aligned(info, dst, src, pitch, width, image.height); info->fbops->fb_imageblit(info, &image); - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); } void accel_putcs(struct vc_data *vc, struct fb_info *info, @@ -676,7 +671,7 @@ if (!info->queue.func) { INIT_WORK(&info->queue, fb_flashcursor, info); - cursor_timer.expires = jiffies + HZ / 50; + cursor_timer.expires = jiffies + HZ / 5; cursor_timer.data = (unsigned long ) info; add_timer(&cursor_timer); } @@ -944,6 +939,8 @@ if (!info->fbops->fb_blank && console_blanked) return; + if (info->state != FBINFO_STATE_RUNNING) + return; if (!height || !width) return; @@ -968,6 +965,8 @@ if (!info->fbops->fb_blank && console_blanked) return; + if (info->state != FBINFO_STATE_RUNNING) + return; if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; @@ -983,6 +982,8 @@ if (!info->fbops->fb_blank && console_blanked) return; + if (info->state != FBINFO_STATE_RUNNING) + return; if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; @@ -2265,6 +2266,39 @@ return 0; } +static void fbcon_suspended(struct fb_info *info) +{ + /* Clear cursor, restore saved data */ + info->cursor.enable = 0; + info->fbops->fb_cursor(info, &info->cursor); +} + +static void fbcon_resumed(struct fb_info *info) +{ + struct vc_data *vc; + + if (info->currcon < 0) + return; + vc = vc_cons[info->currcon].d; + + update_screen(vc->vc_num); +} +static int fbcon_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + struct fb_info *info = (struct fb_info *) data; + + switch(action) { + case FB_EVENT_SUSPEND: + fbcon_suspended(info); + break; + case FB_EVENT_RESUME: + fbcon_resumed(info); + break; + } + return 0; +} + /* * The console `switch' structure for the frame buffer based console */ @@ -2291,16 +2325,35 @@ .con_resize = fbcon_resize, }; +static struct notifier_block fbcon_event_notifer = { + .notifier_call = fbcon_event_notify, +}; + +static int fbcon_event_notifier_registered; + int __init fb_console_init(void) { if (!num_registered_fb) return -ENODEV; take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); + acquire_console_sem(); + if (!fbcon_event_notifier_registered) { + fb_register_client(&fbcon_event_notifer); + fbcon_event_notifier_registered = 1; + } + release_console_sem(); + return 0; } void __exit fb_console_exit(void) { + acquire_console_sem(); + if (fbcon_event_notifier_registered) { + fb_unregister_client(&fbcon_event_notifer); + fbcon_event_notifier_registered = 0; + } + release_console_sem(); give_up_console(&fb_con); } diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c --- a/drivers/video/fbmem.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/fbmem.c Sun Feb 15 23:14:38 2004 @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include #endif @@ -222,6 +223,9 @@ #ifdef CONFIG_FB_RADEON { "radeonfb", radeonfb_init, radeonfb_setup }, #endif +#ifdef CONFIG_FB_RADEON_OLD + { "radeonfb_old", radeonfb_init, radeonfb_setup }, +#endif #ifdef CONFIG_FB_CONTROL { "controlfb", control_init, control_setup }, #endif @@ -395,6 +399,7 @@ static initcall_t pref_init_funcs[FB_MAX]; static int num_pref_init_funcs __initdata = 0; +static struct notifier_block *fb_notifier_list; struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; @@ -463,23 +468,32 @@ */ u32 fb_get_buffer_offset(struct fb_info *info, u32 size) { - u32 align = info->pixmap.buf_align - 1; - u32 offset, count = 1000; + struct fb_pixmap *buf = &info->pixmap; + u32 align = buf->buf_align - 1, offset; - spin_lock(&info->pixmap.lock); - offset = info->pixmap.offset + align; + /* If IO mapped, we need to sync before access, no sharing of + * the pixmap is done + */ + if (buf->flags & FB_PIXMAP_IO) { + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + return 0; + } + + /* See if we fit in the remaining pixmap space */ + offset = buf->offset + align; offset &= ~align; - if (offset + size > info->pixmap.size) { - while (atomic_read(&info->pixmap.count) && count--); - if (info->fbops->fb_sync && - info->pixmap.flags & FB_PIXMAP_SYNC) + if (offset + size > buf->size) { + /* We do not fit. In order to be able to re-use the buffer, + * we must ensure no asynchronous DMA'ing or whatever operation + * is in progress, we sync for that. + */ + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) info->fbops->fb_sync(info); offset = 0; } - info->pixmap.offset = offset + size; - atomic_inc(&info->pixmap.count); - smp_mb__after_atomic_inc(); - spin_unlock(&info->pixmap.lock); + buf->offset = offset + size; + return offset; } @@ -685,8 +699,8 @@ struct fb_image image; int x; - /* Return if the frame buffer is not mapped */ - if (fb_logo.logo == NULL) + /* Return if the frame buffer is not mapped or suspended */ + if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) return 0; image.depth = fb_logo.depth; @@ -732,8 +746,6 @@ x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { image.dx = x; info->fbops->fb_imageblit(info, &image); - //atomic_dec(&info->pixmap.count); - //smp_mb__after_atomic_dec(); } if (palette != NULL) @@ -780,6 +792,9 @@ if (!info || ! info->screen_base) return -ENODEV; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + if (info->fbops->fb_read) return info->fbops->fb_read(file, buf, count, ppos); @@ -815,6 +830,9 @@ if (!info || !info->screen_base) return -ENODEV; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + if (info->fbops->fb_write) return info->fbops->fb_write(file, buf, count, ppos); @@ -941,6 +959,8 @@ fb_pan_display(info, &info->var); fb_set_cmap(&info->cmap, 1, info); + + notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info); } } return 0; @@ -979,7 +999,7 @@ struct fb_con2fbmap con2fb; #endif struct fb_cmap cmap; - int i; + int i, rc; if (!fb) return -ENODEV; @@ -990,7 +1010,9 @@ case FBIOPUT_VSCREENINFO: if (copy_from_user(&var, (void *) arg, sizeof(var))) return -EFAULT; + acquire_console_sem(); i = fb_set_var(info, &var); + release_console_sem(); if (i) return i; if (copy_to_user((void *) arg, &var, sizeof(var))) return -EFAULT; @@ -1009,13 +1031,19 @@ case FBIOPAN_DISPLAY: if (copy_from_user(&var, (void *) arg, sizeof(var))) return -EFAULT; - if ((i = fb_pan_display(info, &var))) + acquire_console_sem(); + i = fb_pan_display(info, &var); + release_console_sem(); + if (i) return i; if (copy_to_user((void *) arg, &var, sizeof(var))) return -EFAULT; return 0; case FBIO_CURSOR: - return (fb_cursor(info, (struct fb_cursor *) arg)); + acquire_console_sem(); + rc = fb_cursor(info, (struct fb_cursor *) arg); + release_console_sem(); + return rc; #ifdef CONFIG_FRAMEBUFFER_CONSOLE case FBIOGET_CON2FBMAP: if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb))) @@ -1045,7 +1073,10 @@ return 0; #endif /* CONFIG_FRAMEBUFFER_CONSOLE */ case FBIOBLANK: - return fb_blank(info, arg); + acquire_console_sem(); + i = fb_blank(info, arg); + release_console_sem(); + return i; default: if (fb->fb_ioctl == NULL) return -EINVAL; @@ -1242,7 +1273,6 @@ fb_info->pixmap.outbuf = sys_outbuf; if (fb_info->pixmap.inbuf == NULL) fb_info->pixmap.inbuf = sys_inbuf; - spin_lock_init(&fb_info->pixmap.lock); registered_fb[i] = fb_info; @@ -1279,8 +1309,42 @@ return 0; } +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return notifier_chain_register(&fb_notifier_list, nb); +} + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return notifier_chain_unregister(&fb_notifier_list, nb); +} + +/** + * fb_set_suspend - low level driver signals suspend + * @info: framebuffer affected + * @state: 0 = resuming, !=0 = suspending + * + * This is meant to be used by low level drivers to + * signal suspend/resume to the core & clients. + * It must be called with the console semaphore held + */ void fb_set_suspend(struct fb_info *info, int state) { + if (state) { + notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, info); + info->state = FBINFO_STATE_SUSPENDED; + } else { + info->state = FBINFO_STATE_RUNNING; + notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, info); + } } /** @@ -1397,5 +1461,7 @@ EXPORT_SYMBOL(move_buf_unaligned); EXPORT_SYMBOL(move_buf_aligned); EXPORT_SYMBOL(fb_set_suspend); +EXPORT_SYMBOL(fb_register_client); +EXPORT_SYMBOL(fb_unregister_client); MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c --- a/drivers/video/riva/fbdev.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/riva/fbdev.c Sun Feb 15 23:14:38 2004 @@ -1615,8 +1615,9 @@ } #ifdef CONFIG_PPC_OF -static int riva_get_EDID_OF(struct riva_par *par, struct pci_dev *pd) +static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) { + struct riva_par *par = (struct riva_par *) info->par; struct device_node *dp; unsigned char *pedid = NULL; diff -Nru a/drivers/video/softcursor.c b/drivers/video/softcursor.c --- a/drivers/video/softcursor.c Sun Feb 15 23:14:38 2004 +++ b/drivers/video/softcursor.c Sun Feb 15 23:14:38 2004 @@ -48,6 +48,9 @@ info->cursor.image.depth = cursor->image.depth; } + if (info->state != FBINFO_STATE_RUNNING) + return 0; + s_pitch = (info->cursor.image.width + 7) >> 3; dsize = s_pitch * info->cursor.image.height; d_pitch = (s_pitch + scan_align) & ~scan_align; @@ -74,8 +77,6 @@ info->cursor.image.data = dst; info->fbops->fb_imageblit(info, &info->cursor.image); - atomic_dec(&info->pixmap.count); - smp_mb__after_atomic_dec(); return 0; } diff -Nru a/include/linux/fb.h b/include/linux/fb.h --- a/include/linux/fb.h Sun Feb 15 23:14:38 2004 +++ b/include/linux/fb.h Sun Feb 15 23:14:38 2004 @@ -340,6 +340,24 @@ struct file; /* + * Register/unregister for framebuffer events + */ + +/* The resolution of the passed in fb_info about to change */ +#define FB_EVENT_MODE_CHANGE 0x01 +/* The display on this fb_info is beeing suspended, no access to the + * framebuffer is allowed any more after that call returns + */ +#define FB_EVENT_SUSPEND 0x02 +/* The display on this fb_info was resumed, you can restore the display + * if you own it + */ +#define FB_EVENT_RESUME 0x03 + +extern int fb_register_client(struct notifier_block *nb); +extern int fb_unregister_client(struct notifier_block *nb); + +/* * Pixmap structure definition * * The purpose of this structure is to translate data @@ -363,8 +381,6 @@ /* access methods */ void (*outbuf)(u8 *dst, u8 *addr, unsigned int size); u8 (*inbuf) (u8 *addr); - spinlock_t lock; /* spinlock */ - atomic_t count; }; /* @@ -449,6 +465,9 @@ struct vc_data *display_fg; /* Console visible on this display */ int currcon; /* Current VC. */ void *pseudo_palette; /* Fake palette of 16 colors */ +#define FBINFO_STATE_RUNNING 0 +#define FBINFO_STATE_SUSPENDED 1 + u32 state; /* Hardware state i.e suspend */ /* From here on everything is device dependent */ void *par; }; diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Sun Feb 15 23:14:38 2004 +++ b/include/linux/pci_ids.h Sun Feb 15 23:14:38 2004 @@ -216,28 +216,37 @@ /* Rage128 GL */ #define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245 #define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 -#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x534b -#define PCI_DEVICE_ID_ATI_RAGE128_RH 0x534c -#define PCI_DEVICE_ID_ATI_RAGE128_RI 0x534d +#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247 /* Rage128 VR */ #define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b #define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c -#define PCI_DEVICE_ID_ATI_RAGE128_RM 0x5345 -#define PCI_DEVICE_ID_ATI_RAGE128_RN 0x5346 -#define PCI_DEVICE_ID_ATI_RAGE128_RO 0x5347 +#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345 +#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346 +#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347 +#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348 +#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b +#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c +#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d +#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e +/* Rage128 Ultra */ +#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446 +#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c +#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 +#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453 +#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454 +#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455 /* Rage128 M3 */ #define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45 #define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46 -/* Rage128 Pro Ultra */ -#define PCI_DEVICE_ID_ATI_RAGE128_U1 0x5446 -#define PCI_DEVICE_ID_ATI_RAGE128_U2 0x544C -#define PCI_DEVICE_ID_ATI_RAGE128_U3 0x5452 +/* Rage128 M4 */ +#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46 +#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c /* Rage128 Pro GL */ -#define PCI_DEVICE_ID_ATI_Rage128_PA 0x5041 -#define PCI_DEVICE_ID_ATI_Rage128_PB 0x5042 -#define PCI_DEVICE_ID_ATI_Rage128_PC 0x5043 -#define PCI_DEVICE_ID_ATI_Rage128_PD 0x5044 -#define PCI_DEVICE_ID_ATI_Rage128_PE 0x5045 +#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041 +#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042 +#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043 +#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044 +#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045 #define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 /* Rage128 Pro VR */ #define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047 diff -Nru a/include/video/aty128.h b/include/video/aty128.h --- a/include/video/aty128.h Sun Feb 15 23:14:38 2004 +++ b/include/video/aty128.h Sun Feb 15 23:14:38 2004 @@ -415,5 +415,8 @@ #define PWR_MGT_SLOWDOWN_MCLK 0x00002000 #define PMI_PMSCR_REG 0x60 + +/* used by ATI bug fix for hardware ROM */ +#define RAGE128_MPP_TB_CONFIG 0x01c0 #endif /* REG_RAGE128_H */ diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c --- a/net/bluetooth/rfcomm/tty.c Sun Feb 15 23:14:38 2004 +++ b/net/bluetooth/rfcomm/tty.c Sun Feb 15 23:14:38 2004 @@ -97,10 +97,16 @@ rfcomm_dlc_unlock(dlc); rfcomm_dlc_put(dlc); + + /* Refcount should only hit zero when called from rfcomm_dev_del() + which will have taken us off the list. Everything else are + refcounting bugs. */ + BUG_ON(!list_empty(&dev->list)); + kfree(dev); /* It's safe to call module_put() here because socket still - holds refference to this module. */ + holds reference to this module. */ module_put(THIS_MODULE); } @@ -111,6 +117,13 @@ static inline void rfcomm_dev_put(struct rfcomm_dev *dev) { + /* The reason this isn't actually a race, as you no + doubt have a little voice screaming at you in your + head, is that the refcount should never actually + reach zero unless the device has already been taken + off the list, in rfcomm_dev_del(). And if that's not + true, we'll hit the BUG() in rfcomm_dev_destruct() + anyway. */ if (atomic_dec_and_test(&dev->refcnt)) rfcomm_dev_destruct(dev); } @@ -134,10 +147,13 @@ struct rfcomm_dev *dev; read_lock(&rfcomm_dev_lock); + dev = __rfcomm_dev_get(id); + if (dev) + rfcomm_dev_hold(dev); + read_unlock(&rfcomm_dev_lock); - if (dev) rfcomm_dev_hold(dev); return dev; } @@ -214,8 +230,9 @@ rfcomm_dlc_unlock(dlc); /* It's safe to call __module_get() here because socket already - holds refference to this module. */ + holds reference to this module. */ __module_get(THIS_MODULE); + out: write_unlock_bh(&rfcomm_dev_lock); @@ -486,7 +503,8 @@ rfcomm_dev_del(dev); /* We have to drop DLC lock here, otherwise - * rfcomm_dev_put() will dead lock if it's the last refference */ + rfcomm_dev_put() will dead lock if it's + the last reference. */ rfcomm_dlc_unlock(dlc); rfcomm_dev_put(dev); rfcomm_dlc_lock(dlc); @@ -541,6 +559,10 @@ BT_DBG("tty %p id %d", tty, id); + /* We don't leak this refcount. For reasons which are not entirely + clear, the TTY layer will call our ->close() method even if the + open fails. We decrease the refcount there, and decreasing it + here too would cause breakage. */ dev = rfcomm_dev_get(id); if (!dev) return -ENODEV; @@ -561,10 +583,8 @@ set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); - if (err < 0) { - rfcomm_dev_put(dev); + if (err < 0) return err; - } /* Wait for DLC to connect */ add_wait_queue(&dev->wait, &wait); @@ -588,9 +608,6 @@ } set_current_state(TASK_RUNNING); remove_wait_queue(&dev->wait, &wait); - - if (err < 0) - rfcomm_dev_put(dev); return err; }