--- grub-0.91/netboot/pci.c.org Thu Jan 3 08:23:29 2002 +++ grub-0.91/netboot/pci.c Thu Mar 21 17:43:38 2002 @@ -499,3 +499,97 @@ pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32); } } + +#define EIO 5 /* I/O error */ +#define EINVAL 22 /* Invalid argument */ + +#define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ + +#define PCI_CB_CAPABILITY_LIST 0x14 + +#define PCI_CAP_LIST_ID 0 /* Capability ID */ +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ + +#define PCI_HEADER_TYPE_NORMAL 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_PM_PMC 2 /* PM Capabilities Register */ +#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ +#define PCI_PM_CTRL 4 /* PM control and status register */ +#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ +#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ +#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ + +static __inline__ int ffs(int x) +{ + int r; + + __asm__("bsfl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r+1; +} + +int +pci_find_capability(int bus, int devfn, int cap) +{ + unsigned short status; + unsigned char pos, id; + int ttl = 48; + + pcibios_read_config_word(bus, devfn, PCI_STATUS, &status); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + pcibios_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos); /* no cardbus */ + while (ttl-- && pos >= 0x40) { + pos &= ~3; + pcibios_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id); + if (id == 0xff) + break; + if (id == cap) + return pos; + pcibios_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos); + } + return 0; +} + +int pci_enable_wake(int bus, int devfn, unsigned int state, int enable) +{ + int pm; + unsigned short value; + + /* find PCI PM capability in list */ + pm = pci_find_capability(bus, devfn, PCI_CAP_ID_PM); + + /* If device doesn't support PM Capabilities, but request is to disable + * wake events, it's a nop; otherwise fail */ + if (!pm) + return enable ? -EIO : 0; + + /* Check device's ability to generate PME# */ + pcibios_read_config_word(bus, devfn, pm+PCI_PM_PMC,&value); + + value &= PCI_PM_CAP_PME_MASK; + value >>= ffs(value); /* First bit of mask */ + + /* Check if it can generate PME# from requested state. */ + if (!value || !(value & (1 << state))) + return enable ? -EINVAL : 0; + + pcibios_read_config_word(bus, devfn, pm + PCI_PM_CTRL, &value); + + /* Clear PME_Status by writing 1 to it and enable PME# */ + value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE; + + if (!enable) + value &= ~PCI_PM_CTRL_PME_ENABLE; + + pcibios_write_config_word(bus, devfn, pm + PCI_PM_CTRL, value); + + return 0; +} --- grub-0.91/netboot/pci.h.org Thu Jan 3 08:23:29 2002 +++ grub-0.91/netboot/pci.h Thu Mar 21 17:43:38 2002 @@ -189,4 +189,8 @@ extern int pcibios_read_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int *value); extern int pcibios_write_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value); void adjust_pci_device(struct pci_device *p); + +int pci_find_capability(int bus, int devfn, int cap); +int pci_enable_wake(int bus, int devfn, unsigned int state, int enable); + #endif /* PCI_H */ --- grub-0.91/netboot/3c90x.c.org Thu Jan 3 08:23:29 2002 +++ grub-0.91/netboot/3c90x.c Thu Mar 21 17:46:51 2002 @@ -917,6 +917,7 @@ a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdAcknowledgeInterrupt, 0x661); + pci_enable_wake(pci->bus, pci->devfn, 0, 1); /** Set our exported functions **/ nic->reset = a3c90x_reset; nic->poll = a3c90x_poll;