Commit 3c4536d8 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/disk1/davem/BK/network-2.5

into nuts.ninka.net:/disk1/davem/BK/net-2.5
parents 76ed4e71 3f5ae09d
......@@ -44,6 +44,11 @@ struct irq_router {
int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
};
struct irq_router_handler {
u16 vendor;
int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device);
};
int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
/*
......@@ -258,111 +263,220 @@ static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
}
/*
* PIRQ routing for SiS 85C503 router used in several SiS chipsets
* According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
* the related registers work as follows:
*
* general: one byte per re-routable IRQ,
* PIRQ routing for SiS 85C503 router used in several SiS chipsets.
* We have to deal with the following issues here:
* - vendors have different ideas about the meaning of link values
* - some onboard devices (integrated in the chipset) have special
* links and are thus routed differently (i.e. not via PCI INTA-INTD)
* - different revision of the router have a different layout for
* the routing registers, particularly for the onchip devices
*
* For all routing registers the common thing is we have one byte
* per routeable link which is defined as:
* bit 7 IRQ mapping enabled (0) or disabled (1)
* bits [6:4] reserved
* bits [6:4] reserved (sometimes used for onchip devices)
* bits [3:0] IRQ to map to
* allowed: 3-7, 9-12, 14-15
* reserved: 0, 1, 2, 8, 13
*
* individual registers in device config space:
* The config-space registers located at 0x41/0x42/0x43/0x44 are
* always used to route the normal PCI INT A/B/C/D respectively.
* Apparently there are systems implementing PCI routing table using
* link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D.
* We try our best to handle both link mappings.
*
* Currently (2003-05-21) it appears most SiS chipsets follow the
* definition of routing registers from the SiS-5595 southbridge.
* According to the SiS 5595 datasheets the revision id's of the
* router (ISA-bridge) should be 0x01 or 0xb0.
*
* 0x41/0x42/0x43/0x44: PCI INT A/B/C/D - bits as in general case
* Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1.
* Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets.
* They seem to work with the current routing code. However there is
* some concern because of the two USB-OHCI HCs (original SiS 5595
* had only one). YMMV.
*
* 0x61: IDEIRQ: bits as in general case - but:
* bits [6:5] must be written 01
* bit 4 channel-select primary (0), secondary (1)
* Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1:
*
* 0x62: USBIRQ: bits as in general case - but:
* bit 4 OHCI function disabled (0), enabled (1)
* 0x61: IDEIRQ:
* bits [6:5] must be written 01
* bit 4 channel-select primary (0), secondary (1)
*
* 0x62: USBIRQ:
* bit 6 OHCI function disabled (0), enabled (1)
*
* 0x6a: ACPI/SCI IRQ - bits as in general case
* 0x6a: ACPI/SCI IRQ: bits 4-6 reserved
*
* 0x7e: Data Acq. Module IRQ - bits 4-6 reserved
*
* We support USBIRQ (in addition to INTA-INTD) and keep the
* IDE, ACPI and DAQ routing untouched as set by the BIOS.
*
* Currently the only reported exception is the new SiS 65x chipset
* which includes the SiS 69x southbridge. Here we have the 85C503
* router revision 0x04 and there are changes in the register layout
* mostly related to the different USB HCs with USB 2.0 support.
*
* 0x7e: Data Acq. Module IRQ - bits as in general case
* Onchip routing for router rev-id 0x04 (try-and-error observation)
*
* Apparently there are systems implementing PCI routing table using both
* link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
* like 0x62 as link values for USBIRQ e.g. So there is no simple
* "register = offset + pirq" relation.
* Currently we support PCI INTA..D and USBIRQ and try our best to handle
* both link mappings.
* IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
* 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs
* bit 6-4 are probably unused, not like 5595
*/
static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
#define PIRQ_SIS_IRQ_MASK 0x0f
#define PIRQ_SIS_IRQ_DISABLE 0x80
#define PIRQ_SIS_USB_ENABLE 0x40
/* return value:
* -1 on error
* 0 for PCI INTA-INTD
* 0 or enable bit mask to check or set for onchip functions
*/
static inline int pirq_sis5595_onchip(int pirq, int *reg)
{
u8 x;
int reg = pirq;
int ret = -1;
*reg = pirq;
switch(pirq) {
case 0x01:
case 0x02:
case 0x03:
case 0x04:
reg += 0x40;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x62:
pci_read_config_byte(router, reg, &x);
if (reg != 0x62)
break;
if (!(x & 0x40))
return 0;
break;
case 0x61:
case 0x6a:
case 0x7e:
printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
return 0;
default:
printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
return 0;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
*reg += 0x40;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
ret = 0;
break;
case 0x62:
ret = PIRQ_SIS_USB_ENABLE; /* documented for 5595 */
break;
case 0x61:
case 0x6a:
case 0x7e:
printk(KERN_INFO "SiS pirq: IDE/ACPI/DAQ mapping not implemented: (%u)\n",
(unsigned) pirq);
/* fall thru */
default:
printk(KERN_INFO "SiS router unknown request: (%u)\n",
(unsigned) pirq);
break;
}
return (x & 0x80) ? 0 : (x & 0x0f);
}
return ret;
}
static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
/* return value:
* -1 on error
* 0 for PCI INTA-INTD
* 0 or enable bit mask to check or set for onchip functions
*/
static inline int pirq_sis96x_onchip(int pirq, int *reg)
{
u8 x;
int reg = pirq;
int ret = -1;
*reg = pirq;
switch(pirq) {
case 0x01:
case 0x02:
case 0x03:
case 0x04:
reg += 0x40;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x62:
x = (irq&0x0f) ? (irq&0x0f) : 0x80;
if (reg != 0x62)
break;
/* always mark OHCI enabled, as nothing else knows about this */
x |= 0x40;
break;
case 0x61:
case 0x6a:
case 0x7e:
printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
return 0;
default:
printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
return 0;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
*reg += 0x40;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x60:
case 0x61:
case 0x62:
case 0x63:
ret = 0;
break;
default:
printk(KERN_INFO "SiS router unknown request: (%u)\n",
(unsigned) pirq);
break;
}
return ret;
}
static int pirq_sis5595_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
u8 x;
int reg, check;
check = pirq_sis5595_onchip(pirq, &reg);
if (check < 0)
return 0;
pci_read_config_byte(router, reg, &x);
if (check != 0 && !(x & check))
return 0;
return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
}
static int pirq_sis96x_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
u8 x;
int reg, check;
check = pirq_sis96x_onchip(pirq, &reg);
if (check < 0)
return 0;
pci_read_config_byte(router, reg, &x);
if (check != 0 && !(x & check))
return 0;
return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
}
static int pirq_sis5595_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
u8 x;
int reg, set;
set = pirq_sis5595_onchip(pirq, &reg);
if (set < 0)
return 0;
x = (irq & PIRQ_SIS_IRQ_MASK);
if (x == 0)
x = PIRQ_SIS_IRQ_DISABLE;
else
x |= set;
pci_write_config_byte(router, reg, x);
return 1;
}
static int pirq_sis96x_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
u8 x;
int reg, set;
set = pirq_sis96x_onchip(pirq, &reg);
if (set < 0)
return 0;
x = (irq & PIRQ_SIS_IRQ_MASK);
if (x == 0)
x = PIRQ_SIS_IRQ_DISABLE;
else
x |= set;
pci_write_config_byte(router, reg, x);
return 1;
}
/*
* VLSI: nibble offset 0x74 - educated guess due to routing table and
* config space of VLSI 82C534 PCI-bridge/router (1004:0102)
......@@ -455,96 +569,252 @@ static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
return pcibios_set_irq_routing(bridge, pin, irq);
}
static struct irq_router pirq_bios_router =
{ "BIOS", 0, 0, NULL, pirq_bios_set };
#endif
static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
#if 0 /* Let's see what chip this is supposed to be ... */
/* We must not touch 440GX even if we have tables. 440GX has
different IRQ routing weirdness */
if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82440GX, NULL))
return 0;
#endif
static struct irq_router pirq_routers[] = {
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_0, pirq_piix_get, pirq_piix_set },
{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
pirq_serverworks_get, pirq_serverworks_set },
{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
pirq_serverworks_get, pirq_serverworks_set },
{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
pirq_amd756_get, pirq_amd756_set },
{ "AMD766", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413,
pirq_amd756_get, pirq_amd756_set },
{ "AMD768", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443,
pirq_amd756_get, pirq_amd756_set },
{ "default", 0, 0, NULL, NULL }
};
switch(device)
{
case PCI_DEVICE_ID_INTEL_82371FB_0:
case PCI_DEVICE_ID_INTEL_82371SB_0:
case PCI_DEVICE_ID_INTEL_82371AB_0:
case PCI_DEVICE_ID_INTEL_82371MX:
case PCI_DEVICE_ID_INTEL_82443MX_0:
case PCI_DEVICE_ID_INTEL_82801AA_0:
case PCI_DEVICE_ID_INTEL_82801AB_0:
case PCI_DEVICE_ID_INTEL_82801BA_0:
case PCI_DEVICE_ID_INTEL_82801BA_10:
case PCI_DEVICE_ID_INTEL_82801CA_0:
case PCI_DEVICE_ID_INTEL_82801CA_12:
case PCI_DEVICE_ID_INTEL_82801DB_0:
case PCI_DEVICE_ID_INTEL_82801E_0:
case PCI_DEVICE_ID_INTEL_82801EB_0:
case PCI_DEVICE_ID_INTEL_ESB_0:
r->name = "PIIX/ICH";
r->get = pirq_piix_get;
r->set = pirq_piix_set;
return 1;
}
return 0;
}
static struct irq_router *pirq_router;
static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
/* FIXME: We should move some of the quirk fixup stuff here */
switch(device)
{
case PCI_DEVICE_ID_VIA_82C586_0:
case PCI_DEVICE_ID_VIA_82C596:
case PCI_DEVICE_ID_VIA_82C686:
case PCI_DEVICE_ID_VIA_8231:
/* FIXME: add new ones for 8233/5 */
r->name = "VIA";
r->get = pirq_via_get;
r->set = pirq_via_set;
return 1;
}
return 0;
}
static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_VLSI_82C534:
r->name = "VLSI 82C534";
r->get = pirq_vlsi_get;
r->set = pirq_vlsi_set;
return 1;
}
return 0;
}
static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_SERVERWORKS_OSB4:
case PCI_DEVICE_ID_SERVERWORKS_CSB5:
r->name = "ServerWorks";
r->get = pirq_serverworks_get;
r->set = pirq_serverworks_set;
return 1;
}
return 0;
}
static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
if (device != PCI_DEVICE_ID_SI_503)
return 0;
/*
* In case of SiS south bridge, we need to detect the two
* kinds of routing tables we have seen so far (5595 and 96x).
*
* The 96x tends to still come with routing tables that claim
* to be 503's.. Silly thing. Check the actual router chip.
*/
if ((router->device & 0xfff0) == 0x0960) {
r->name = "SIS96x";
r->get = pirq_sis96x_get;
r->set = pirq_sis96x_set;
DBG("PCI: Detecting SiS router at %02x:%02x : SiS096x detected\n",
rt->rtr_bus, rt->rtr_devfn);
} else {
r->name = "SIS5595";
r->get = pirq_sis5595_get;
r->set = pirq_sis5595_set;
DBG("PCI: Detecting SiS router at %02x:%02x : SiS5595 detected\n",
rt->rtr_bus, rt->rtr_devfn);
}
return 1;
}
static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_CYRIX_5520:
r->name = "NatSemi";
r->get = pirq_cyrix_get;
r->set = pirq_cyrix_set;
return 1;
}
return 0;
}
static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_OPTI_82C700:
r->name = "OPTI";
r->get = pirq_opti_get;
r->set = pirq_opti_set;
return 1;
}
return 0;
}
static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_ITE_IT8330G_0:
r->name = "ITE";
r->get = pirq_ite_get;
r->set = pirq_ite_set;
return 1;
}
return 0;
}
static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_AL_M1533:
r->name = "ALI";
r->get = pirq_ali_get;
r->set = pirq_ali_set;
return 1;
/* Should add 156x some day */
}
return 0;
}
static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_AMD_VIPER_740B:
r->name = "AMD756";
break;
case PCI_DEVICE_ID_AMD_VIPER_7413:
r->name = "AMD766";
break;
case PCI_DEVICE_ID_AMD_VIPER_7443:
r->name = "AMD768";
break;
default:
return 0;
}
r->get = pirq_amd756_get;
r->set = pirq_amd756_set;
return 1;
}
static __initdata struct irq_router_handler pirq_routers[] = {
{ PCI_VENDOR_ID_INTEL, intel_router_probe },
{ PCI_VENDOR_ID_AL, ali_router_probe },
{ PCI_VENDOR_ID_ITE, ite_router_probe },
{ PCI_VENDOR_ID_VIA, via_router_probe },
{ PCI_VENDOR_ID_OPTI, opti_router_probe },
{ PCI_VENDOR_ID_SI, sis_router_probe },
{ PCI_VENDOR_ID_CYRIX, cyrix_router_probe },
{ PCI_VENDOR_ID_VLSI, vlsi_router_probe },
{ PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
{ PCI_VENDOR_ID_AMD, amd_router_probe },
/* Someone with docs needs to add the ATI Radeon IGP */
{ 0, NULL }
};
static struct irq_router pirq_router;
static struct pci_dev *pirq_router_dev;
static void __init pirq_find_router(void)
/*
* FIXME: should we have an option to say "generic for
* chipset" ?
*/
static void __init pirq_find_router(struct irq_router *r)
{
struct irq_routing_table *rt = pirq_table;
struct irq_router *r;
struct irq_router_handler *h;
#ifdef CONFIG_PCI_BIOS
if (!rt->signature) {
printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
pirq_router = &pirq_bios_router;
r->set = pirq_bios_set;
r->name = "BIOS";
return;
}
#endif
/* Default unless a driver reloads it */
r->name = "default";
r->get = NULL;
r->set = NULL;
DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
rt->rtr_vendor, rt->rtr_device);
/* fall back to default router if nothing else found */
pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
if (!pirq_router_dev) {
DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
return;
}
for(r=pirq_routers; r->vendor; r++) {
/* Exact match against router table entry? Use it! */
if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
pirq_router = r;
for( h = pirq_routers; h->vendor; h++) {
/* First look for a router match */
if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device))
break;
/* Fall back to a device match */
if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device))
break;
}
/* Match against router device entry? Use it as a fallback */
if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
pirq_router = r;
}
}
printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
pirq_router->name,
pirq_router.name,
pirq_router_dev->vendor,
pirq_router_dev->device,
pci_name(pirq_router_dev));
......@@ -574,7 +844,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
int i, pirq, newirq;
int irq = 0;
u32 mask;
struct irq_router *r = pirq_router;
struct irq_router *r = &pirq_router;
struct pci_dev *dev2 = NULL;
char *msg = NULL;
......@@ -775,7 +1045,7 @@ static int __init pcibios_irq_init(void)
#endif
if (pirq_table) {
pirq_peer_trick();
pirq_find_router();
pirq_find_router(&pirq_router);
if (pirq_table->exclusive_irqs) {
int i;
for (i=0; i<16; i++)
......
/*
* Version 2.11
* Version 2.13
*
* AMD 755/756/766/8111 and nVidia nForce IDE driver for Linux.
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s IDE driver for Linux.
*
* Copyright (c) 2000-2002 Vojtech Pavlik
*
......@@ -40,9 +40,11 @@
#define AMD_UDMA_33 0x01
#define AMD_UDMA_66 0x02
#define AMD_UDMA_100 0x03
#define AMD_UDMA_133 0x04
#define AMD_CHECK_SWDMA 0x08
#define AMD_BAD_SWDMA 0x10
#define AMD_BAD_FIFO 0x20
#define AMD_CHECK_SERENADE 0x40
/*
* AMD SouthBridge chips.
......@@ -50,27 +52,33 @@
static struct amd_ide_chip {
unsigned short id;
unsigned char rev;
unsigned long base;
unsigned char flags;
} amd_ide_chips[] = {
{ PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA }, /* AMD-755 Cobra */
{ PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA }, /* AMD-756 Viper */
{ PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO }, /* AMD-766 Viper */
{ PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, 0x40, AMD_UDMA_100 }, /* AMD-768 Opus */
{ PCI_DEVICE_ID_AMD_8111_IDE, 0x00, 0x40, AMD_UDMA_100 }, /* AMD-8111 */
{ PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x00, 0x50, AMD_UDMA_100 }, /* nVidia nForce */
{ PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x00, 0x50, AMD_UDMA_100 }, /* nVidia nForce 2 */
{ PCI_DEVICE_ID_AMD_COBRA_7401, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },
{ PCI_DEVICE_ID_AMD_VIPER_7409, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA },
{ PCI_DEVICE_ID_AMD_VIPER_7411, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO },
{ PCI_DEVICE_ID_AMD_OPUS_7441, 0x40, AMD_UDMA_100 },
{ PCI_DEVICE_ID_AMD_8111_IDE, 0x40, AMD_UDMA_133 | AMD_CHECK_SERENADE },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x50, AMD_UDMA_100 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 },
{ 0 }
};
static struct amd_ide_chip *amd_config;
static ide_pci_device_t *amd_chipset;
static unsigned int amd_80w;
static unsigned int amd_clock;
static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3 };
static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 1 };
static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 15 };
static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
/*
* AMD /proc entry.
......@@ -102,7 +110,7 @@ static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
amd_print("----------AMD BusMastering IDE Configuration----------------");
amd_print("Driver Version: 2.11");
amd_print("Driver Version: 2.13");
amd_print("South Bridge: %s", pci_name(bmide_dev));
pci_read_config_byte(dev, PCI_REVISION_ID, &t);
......@@ -153,6 +161,12 @@ static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
continue;
}
if (den[i] && uen[i] && udma[i] == 15) {
speed[i] = amd_clock * 4;
cycle[i] = 500000 / amd_clock;
continue;
}
speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2);
cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2;
}
......@@ -198,6 +212,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
case AMD_UDMA_33: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
case AMD_UDMA_66: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
case AMD_UDMA_133: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 15)]) : 0x03; break;
default: return;
}
......@@ -232,6 +247,7 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
}
if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
......@@ -271,7 +287,8 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive)
XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0));
(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0) |
(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_133 ? XFER_UDMA_133 : 0));
amd_set_drive(drive, speed);
......@@ -307,13 +324,15 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char
switch (amd_config->flags & AMD_UDMA) {
case AMD_UDMA_133:
case AMD_UDMA_100:
pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
for (i = 24; i >= 0; i -= 8)
if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits correctly. Enabling workaround.\n");
printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n",
amd_chipset->name);
amd_80w |= (1 << (1 - (i >> 4)));
}
break;
......@@ -334,6 +353,15 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char
pci_write_config_byte(dev, AMD_IDE_CONFIG,
(amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
/*
* Take care of incorrectly wired Serenade mainboards.
*/
if ((amd_config->flags & AMD_CHECK_SERENADE) &&
dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
amd_config->flags = AMD_UDMA_100;
/*
* Determine the system bus clock.
*/
......@@ -347,8 +375,10 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char
}
if (amd_clock < 20000 || amd_clock > 50000) {
printk(KERN_WARNING "AMD_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", amd_clock);
printk(KERN_WARNING "AMD_IDE: Use ide0=ata66 if you want to assume 80-wire cable\n");
printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n",
amd_chipset->name, amd_clock);
printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n",
amd_chipset->name);
amd_clock = 33333;
}
......@@ -357,8 +387,8 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char
*/
pci_read_config_byte(dev, PCI_REVISION_ID, &t);
printk(KERN_INFO "AMD_IDE: %s (rev %02x) %s controller on pci%s\n",
pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA], pci_name(dev));
printk(KERN_INFO "%s: %s (rev %02x) %s controller\n",
amd_chipset->name, pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA]);
/*
* Register /proc/ide/amd74xx entry
......@@ -373,8 +403,7 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char
}
#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */
return 0;
return dev->irq;
}
static void __init init_hwif_amd74xx(ide_hwif_t *hwif)
......@@ -414,23 +443,29 @@ extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
ide_pci_device_t *d = amd74xx_chipsets + id->driver_data;
amd_chipset = amd74xx_chipsets + id->driver_data;
amd_config = amd_ide_chips + id->driver_data;
if (dev->device != d->device) BUG();
if (dev->device != amd_chipset->device) BUG();
if (dev->device != amd_config->id) BUG();
ide_setup_pci_device(dev, d);
ide_setup_pci_device(dev, amd_chipset);
MOD_INC_USE_COUNT;
return 0;
}
static struct pci_device_id amd74xx_pci_tbl[] = {
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
{ 0, },
};
......
......@@ -109,6 +109,72 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
.bootable = ON_BOARD,
.extra = 0,
},
{ /* 7 */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,
.name = "NFORCE2S",
.init_chipset = init_chipset_amd74xx,
.init_hwif = init_hwif_amd74xx,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
.bootable = ON_BOARD,
},
{ /* 8 */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
.name = "NFORCE2S-SATA",
.init_chipset = init_chipset_amd74xx,
.init_hwif = init_hwif_amd74xx,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
.bootable = ON_BOARD,
},
{ /* 9 */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,
.name = "NFORCE3",
.init_chipset = init_chipset_amd74xx,
.init_hwif = init_hwif_amd74xx,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
.bootable = ON_BOARD,
},
{ /* 10 */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,
.name = "NFORCE3S",
.init_chipset = init_chipset_amd74xx,
.init_hwif = init_hwif_amd74xx,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
.bootable = ON_BOARD,
},
{ /* 11 */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
.name = "NFORCE3S-SATA",
.init_chipset = init_chipset_amd74xx,
.init_hwif = init_hwif_amd74xx,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
.bootable = ON_BOARD,
},
{ /* 12 */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
.name = "NFORCE3S-SATA2",
.init_chipset = init_chipset_amd74xx,
.init_hwif = init_hwif_amd74xx,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
.bootable = ON_BOARD,
},
{
.vendor = 0,
.device = 0,
......
......@@ -440,6 +440,7 @@
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
#define PCI_DEVICE_ID_AMD_SCSI 0x2020
#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0
#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006
#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007
#define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C
......@@ -1023,7 +1024,13 @@
#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C
#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D
#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065
#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085
#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e
#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0
#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5
#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3
#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5
#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee
#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100
#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101
#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment