Skip to contentSkip to conversation

Promise 20268 PCI register decoding

DISCUSSION Gerald Champagne 3 participants 4 messages Jan 17, 2002

lore
Share & tools
lore
#0 lore raw

I thought I understood the way PCI devices are accessed in Linux, but the code for the Promise PCI controllers has me confused. To me it looks like the code is accessing registers outside the area allocated to the PCI device during initialization.

The device is configured with the following resources (on a Mips-based platform):

00:08.0 Class 0180: 105a:4d68 (rev 01)

        I/O at 0x00000080 [size=0x8]
        I/O at 0x00000088 [size=0x4]
        I/O at 0x00000090 [size=0x8]
        I/O at 0x00000098 [size=0x4]
        I/O at 0x000000a0 [size=0x10]
        Mem at 0x08004000 [size=0x4000]

The Promise code uses registers specified using bar4 but it uses offsets above 0x0f. Here's an example of the code in drivers/ide/pdc202xx.c:

void pdc202xx_reset (ide_drive_t *drive)

{
        unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
        byte udma_speed_flag    = inb(high_16 + 0x001f);

        OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
        mdelay(100);
        OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
        mdelay(2000);           /* 2 seconds ?! */
}

How can the code above try to write to a register 0x1f into a region with a size of 0x10? Wouldn't that stomp on the registers of some other PCI device?

Thanks.

Gerald

#1 lore raw

I fixed that problem after it was discovered.
It is in the newest drivers.

Quoted 43 lines · Gerald Champagne

I thought I understood the way PCI devices are accessed in Linux, but the code for the Promise PCI controllers has me confused. To me it looks like the code is accessing registers outside the area allocated to the PCI device during initialization.

The device is configured with the following resources (on a Mips-based platform):

00:08.0 Class 0180: 105a:4d68 (rev 01)

         I/O at 0x00000080 [size=0x8]
         I/O at 0x00000088 [size=0x4]
         I/O at 0x00000090 [size=0x8]
         I/O at 0x00000098 [size=0x4]
         I/O at 0x000000a0 [size=0x10]
         Mem at 0x08004000 [size=0x4000]

The Promise code uses registers specified using bar4 but it uses offsets above 0x0f. Here's an example of the code in drivers/ide/pdc202xx.c:

void pdc202xx_reset (ide_drive_t *drive)

{
         unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
         byte udma_speed_flag    = inb(high_16 + 0x001f);

         OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
         mdelay(100);
         OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
         mdelay(2000);           /* 2 seconds ?! */
}

How can the code above try to write to a register 0x1f into a region with a size of 0x10? Wouldn't that stomp on the registers of some other PCI device?

Thanks.

Gerald

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#2 lore raw

I just checked 2.5.3-pre1 and it still makes references to
registers above 0x0f. I see many references to registers
at 0x11, 0x1b, 0x1f. For example, the following:

unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x00);

That assumes atapi_reg will be 0x24 beyond the base of bar4 (high_16). Is my PCI code showing me an incorrect size for bar4, or is this accessing registers beyond its limits?

Thanks.

Gerald

Quoted 55 lines · Andre Hedrick

I fixed that problem after it was discovered.
It is in the newest drivers.

Quoted 44 lines · Gerald Champagne

I thought I understood the way PCI devices are accessed in Linux, but the code for the Promise PCI controllers has me confused. To me it looks like the code is accessing registers outside the area allocated to the PCI device during initialization.

The device is configured with the following resources (on a Mips-based platform):

00:08.0 Class 0180: 105a:4d68 (rev 01)

        I/O at 0x00000080 [size=0x8]
        I/O at 0x00000088 [size=0x4]
        I/O at 0x00000090 [size=0x8]
        I/O at 0x00000098 [size=0x4]
        I/O at 0x000000a0 [size=0x10]
        Mem at 0x08004000 [size=0x4000]

The Promise code uses registers specified using bar4 but it uses offsets above 0x0f. Here's an example of the code in drivers/ide/pdc202xx.c:

void pdc202xx_reset (ide_drive_t *drive)

{
        unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
        byte udma_speed_flag    = inb(high_16 + 0x001f);

        OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
        mdelay(100);
        OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
        mdelay(2000);           /* 2 seconds ?! */
}

How can the code above try to write to a register 0x1f into a region with a size of 0x10? Wouldn't that stomp on the registers of some other PCI device?

Thanks.

Gerald

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#3 lore raw
Quoted 9 lines · Gerald Champagne

I just checked 2.5.3-pre1 and it still makes references to
registers above 0x0f. I see many references to registers
at 0x11, 0x1b, 0x1f. For example, the following:

unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x00);

That assumes atapi_reg will be 0x24 beyond the base of bar4 (high_16). Is my PCI code showing me an incorrect size for bar4, or is this accessing registers beyond its limits?

Look in ide-pci.c

cat /proc/ioports | grep 20267 df00-df3f : Promise Technology, Inc. 20267
df10-df3f : PDC20267
dfa0-dfa7 : Promise Technology, Inc. 20267 dfa8-dfab : Promise Technology, Inc. 20267 dfac-dfaf : Promise Technology, Inc. 20267 dfe0-dfe7 : Promise Technology, Inc. 20267

pci bus 0x0 cardnum 0x03 function 0x0000: vendor 0x105a device 0x4d30
Device unknown
CardVendor 0x105a card 0x4d39 (Card unknown)

  STATUS    0x0210  COMMAND 0x0007
  CLASS     0x01 0x04 0x00  REVISION 0x02
  BIST      0x00  HEADER 0x00  LATENCY 0x40  CACHE 0x00
  BASE0     0x0000dfe1  addr 0x0000dfe0  I/O
  BASE1     0x0000dfad  addr 0x0000dfac  I/O
  BASE2     0x0000dfa1  addr 0x0000dfa0  I/O
  BASE3     0x0000dfa9  addr 0x0000dfa8  I/O
  BASE4     0x0000df01  addr 0x0000df00  I/O
  BASE5     0xfeaa0000  addr 0xfeaa0000  MEM
  BASEROM   0xfeae0001  addr 0xfeae0000  decode-enabled
  MAX_LAT   0x00  MIN_GNT 0x00  INT_PIN 0x01  INT_LINE 0x0b
        {DEVID_PDC20246,"PDC20246",     PCI_PDC202XX,   NULL,
INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
OFF_BOARD,
16 },
        {DEVID_PDC20262,"PDC20262",     PCI_PDC202XX,   ATA66_PDC202XX,
INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
OFF_BOARD,
48 },
        {DEVID_PDC20265,"PDC20265",     PCI_PDC202XX,   ATA66_PDC202XX,
INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
OFF_BOARD,
48 },
        {DEVID_PDC20267,"PDC20267",     PCI_PDC202XX,   ATA66_PDC202XX,
INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
OFF_BOARD,
48 },
        {DEVID_PDC20268,"PDC20268",     PCI_PDC202XX,   ATA66_PDC202XX,
INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
OFF_BOARD,
0 },
        {DEVID_PDC20268R,"PDC20270",    PCI_PDC202XX,   ATA66_PDC202XX,
INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
OFF_BOARD,
0 },
        {DEVID_PDC20269,"PDC20269",     PCI_PDC202XX,   ATA66_PDC202XX,
INIT_PDC202XX, NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
OFF_BOARD,
0 },
        {DEVID_PDC20275,"PDC20275",     PCI_PDC202XX,   ATA66_PDC202XX,

INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
OFF_BOARD,
0 },

int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)

        switch (dev->device) {
                case PCI_DEVICE_ID_PROMISE_20275:
                case PCI_DEVICE_ID_PROMISE_20269:
                case PCI_DEVICE_ID_PROMISE_20268R:
                case PCI_DEVICE_ID_PROMISE_20268:
                        newchip = 1;
                        break;
                case PCI_DEVICE_ID_PROMISE_20267:
                case PCI_DEVICE_ID_PROMISE_20265:
                case PCI_DEVICE_ID_PROMISE_20262:
                        hardware48hack = 1;
                        clock = IN_BYTE(high_16 + 0x11);
                default:
                        break;
        }

See above that 62/65/67 have 48 extra io registers.

This it is legal to touch and use them.

Cheers,

Andre Hedrick
Linux Disk Certification Project Linux ATA Development