On -10.01.-28163 20:59, Frederic Temporelli wrote:
> Hello,
> 
> 
> Here's  a patch for using SPI from AMD SouthBridge (SB700, SP5100, ...)
> without  having issue with Integrated MicroControler  (IMC) .
> This issue has been reported by Carl-Daniel Hailfinger in ChangeSet 1173
> http://flashrom.org/trac/flashrom/changeset/1173
> AMD is now providing details about SP5100 register in document 44413:
> http://support.amd.com/us/Embedded_TechDocs/44413.pdf
> In this document (rev 3.02), we can see that a register is in charge of 
> managing access to LPC (p 271 and 283)
> With this patch, we take LPC ownership before each set of commands to SPI.
> Ownership is released when command is done.
> So, there's no more SPI corrupted command due to the IMC. 
> Note: this patch doesn't remove the write protection.
> A second patch will be in charge of removing this write protection.
> 
> Signed-off-by: Frederic Temporelli <[email protected]>
> 
> ---
> The first patch attached to my previous mail has been corrected
> according to Stefan and Paul recommandations. Many thanks
> 
> --
> Fred
> 
> -----Stefan Tauner <[email protected]> a écrit : -----
> A : [email protected]
> De : Stefan Tauner <[email protected]>
> Date : 01/08/2011 12:02
> Cc : [email protected]
> Objet : Re: [flashrom] AMD - SP5100 - take SPI ownership (1/2)
> 
> hello frederic,
> 
> thanks for your patches.
> i have not looked at it in detail yet (i'll leave that to those who are
> more familiar with the IMC problem), but i have spotted quite some
> coding style issues. it would be great if you could fix those.
> i'll explain what i noticed inline.
> 
> On Mon, 1 Aug 2011 10:45:24 +0200
> [email protected] wrote:
> 
>> diff -ur ../flashrom-0.9.4-r1394/sb600spi.c ./sb600spi.c
>> --- ../flashrom-0.9.4-r1394/sb600spi.c       2011-05-11 13:07:07.000000000 
>> -0400
>> +++ ./sb600spi.c     2011-07-29 22:45:48.693159918 -0400
>> @@ -5,6 +5,8 @@
>>   * Copyright (C) 2008 Joe Bao <[email protected]>
>>   * Copyright (C) 2008 Advanced Micro Devices, Inc.
>>   * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
>> + * Copyright (C) 2011 Bull SAS
>> + * (Written by Frederic Temporelli <[email protected]> for Bull 
>> SAS )
> space before the closing parenthesis
> 
>>   *
>>   * This program is free software; you can redistribute it and/or modify
>>   * it under the terms of the GNU General Public License as published by
>> @@ -43,6 +45,63 @@
>>  
>>  static uint8_t *sb600_spibar = NULL;
>>  
>> +/* reference to LPC/SPI PCI device,
>> + * requested for requesting/releasing
>> + * device access, shared with IMC
>> + */ 
>> +struct pci_dev *lpc_isa_bridge = NULL;
>> +
>> +
>> +/*
>> + * avoid interaction from IMC while we are working with LPC/SPI
>> + * this is done by requesting HostOwnLPC register (LPC_ISA_BRIDGE, write 1 
>> in register 0x98)
> line too long, please split (and some punctuation would increase readability 
> then)
> 
>> + * then we have to read this register.
>> + * Loop until we have the ownership
>> + * see doc AMD 44413 - AMD SP5100 Register Reference Guide
>> + */
>> +static int resquest_lpc_ownership (void)
>> +{
>> +    uint8_t tmp;
>> +    int i = 0;
>> +
>> +    if (lpc_isa_bridge == NULL)
>> +            return 1;
>> +
>> +    pci_write_byte(lpc_isa_bridge, 0x98, 0x01);
>> +
>> +    while ( (tmp = pci_read_byte (lpc_isa_bridge, 0x98)) == 0 ){
> we don't use inner space around clauses like here '( (' and '0 )' usually.
> also there is a space missing between ')' and '{'
> 
>> +            pci_write_byte(lpc_isa_bridge, 0x98, 0x01);
>> +            if (++i > 1024) {
>> +                    msg_perr("IMC did not release flash.\n");
>> +                    return 1;
>> +            }
>> +
>> +    }
>> +    msg_pspew("flash ownership after %i cycles.\n", i);
>> +    i = 0;
> please drop the line above completely
> 
>> +    return 0;
>> +}
>> +
>> +
> one line break between functions please
> 
>> +/*
>> + * release LPC/SPI ownership (IMC can access to these resources)
>> + * this is done by releasing HostOwnLPC register
>> + * (write 0 in register 0x98)
>> + */
>> +static int release_lpc_ownership (void)
>> +{
>> +
>> +    if (lpc_isa_bridge == NULL)
>> +            return 1;
>> +
> 
> spaces instead of tabs in the following lines:
>> +        pci_write_byte(lpc_isa_bridge, 0x98, 0x00);
>> +
>> +        msg_pspew("flash ownership is released.\n");
>> +        return 0;
>> +}
>> +
>> +
>> +
> one line break between functions please
> 
>>  static void reset_internal_fifo_pointer(void)
>>  {
>>      mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
>> @@ -93,6 +152,8 @@
>>                    const unsigned char *writearr, unsigned char *readarr)
>>  {
>>      int count;
> spaces instead of tabs
>> +        int result = 0;
>> +
>>      /* First byte is cmd which can not being sent through FIFO. */
>>      unsigned char cmd = *writearr++;
>>      unsigned int readoffby1;
>> @@ -103,16 +164,26 @@
>>      msg_pspew("%s, cmd=%x, writecnt=%x, readcnt=%x\n",
>>                __func__, cmd, writecnt, readcnt);
>>  
>> +    if (resquest_lpc_ownership() != 0){
> space missing between ')' and '{'
> 
>> +            result = SPI_PROGRAMMER_ERROR;
>> +            msg_pinfo("can't take ownership of LPC/SPI");
>> +            goto return_status;
>> +    }
>> + 
>> +
>>      if (readcnt > 8) {
>>              msg_pinfo("%s, SB600 SPI controller can not receive %d bytes, "
>>                     "it is limited to 8 bytes\n", __func__, readcnt);
>> -            return SPI_INVALID_LENGTH;
>> +
>> +            result = SPI_INVALID_LENGTH;
>> +            goto return_status;
>>      }
>>  
>>      if (writecnt > 8) {
>>              msg_pinfo("%s, SB600 SPI controller can not send %d bytes, "
>>                     "it is limited to 8 bytes\n", __func__, writecnt);
>> -            return SPI_INVALID_LENGTH;
>> +            result = SPI_INVALID_LENGTH;
>> +            goto return_status;
>>      }
>>  
>>      /* This is a workaround for a bug in SB600 and SB700. If we only send
>> @@ -142,7 +213,10 @@
>> ÿ     * the FIFO pointer to the first byte we want to send.
>> ÿ     */
>> ÿ    if (reset_compare_internal_fifo_pointer(writecnt))
>> -            return SPI_PROGRAMMER_ERROR;
>> +    {
> the '{' should be in the same line as the 'if'
>> +            result = SPI_PROGRAMMER_ERROR;
>> +            goto return_status;
>> +    }
>> ÿ
>> ÿ    msg_pspew("Executing: \n");
>> ÿ    execute_command();
>> @@ -159,7 +233,10 @@
>> ÿ     * Usually, the chip will respond with 0x00 or 0xff.
>> ÿ     */
>> ÿ    if (reset_compare_internal_fifo_pointer(writecnt + readcnt))
>> -            return SPI_PROGRAMMER_ERROR;
>> +    {
> here too
>> +            result = SPI_PROGRAMMER_ERROR;
>> +            goto return_status;
>> +    }
>> ÿ
>> ÿ    /* Skip the bytes we sent. */
>> ÿ    msg_pspew("Skipping: ");
>> @@ -168,8 +245,11 @@
>> ÿ            msg_pspew("[%02x]", cmd);
>> ÿ    }
>> ÿ    msg_pspew("\n");
>> -    if (compare_internal_fifo_pointer(writecnt))
>> -            return SPI_PROGRAMMER_ERROR;
>> +    if (compare_internal_fifo_pointer(writecnt)){
> missing space
> 
>> +
>> +            result = SPI_PROGRAMMER_ERROR;
>> +            goto return_status;
>> +    }
>> ÿ
>> ÿ    msg_pspew("Reading: ");
>> ÿ    for (count = 0; count < readcnt; count++, readarr++) {
>> @@ -177,8 +257,11 @@
>> ÿ            msg_pspew("[%02x]", *readarr);
>> ÿ    }
>> ÿ    msg_pspew("\n");
>> -    if (reset_compare_internal_fifo_pointer(readcnt + writecnt))
>> -            return SPI_PROGRAMMER_ERROR;
>> +    if (reset_compare_internal_fifo_pointer(readcnt + writecnt)) {
>> +
>> +            result = SPI_PROGRAMMER_ERROR;
>> +            goto return_status;
>> +    }
>> ÿ
>> ÿ    if (mmio_readb(sb600_spibar + 1) != readwrite) {
>> ÿ            msg_perr("Unexpected change in SB600 read/write count!\n");
>> @@ -186,10 +269,12 @@
>> ÿ                     "causes random corruption.\nPlease stop all "
>> ÿ                     "applications and drivers and IPMI which access the "
>> ÿ                     "flash chip.\n");
>> -            return SPI_PROGRAMMER_ERROR;
>> +            result = SPI_PROGRAMMER_ERROR;
>> ÿ    }
>> ÿ
>> -    return 0;
>> +return_status:
>> +    release_lpc_ownership();
>> +    return result;
>> ÿ}
>> ÿ
>> ÿstatic const struct spi_programmer spi_programmer_sb600 = {
>> @@ -211,6 +296,9 @@
>> ÿ            "Reserved", "33", "22", "16.5"
>> ÿ    };
>> ÿ
>> +
>> +    lpc_isa_bridge = dev;
>> +
>> ÿ    /* Read SPI_BaseAddr */
>> ÿ    tmp = pci_read_long(dev, 0xa0);
>> ÿ    tmp &= 0xffffffe0;      /* remove bits 4-0 (reserved) */
> 
> diff -ur ../flashrom-0.9.4-r1394/sb600spi.c ./sb600spi.c
> --- ../flashrom-0.9.4-r1394/sb600spi.c        2011-05-11 13:07:07.000000000 
> -0400
> +++ ./sb600spi.c      2011-08-01 21:17:40.573417039 -0400
> @@ -5,6 +5,8 @@
>   * Copyright (C) 2008 Joe Bao <[email protected]>
>   * Copyright (C) 2008 Advanced Micro Devices, Inc.
>   * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
> + * Copyright (C) 2011 Bull SAS
> + * (Written by Frederic Temporelli <[email protected]> for Bull 
> SAS)
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published by
> @@ -43,6 +45,60 @@
>  
>  static uint8_t *sb600_spibar = NULL;
>  
> +/* reference to LPC/SPI PCI device,
> + * requested for requesting/releasing
> + * device access, shared with IMC
> + */ 
> +struct pci_dev *lpc_isa_bridge = NULL;
> +
> +
> +/*
> + * avoid interaction from IMC, while we are working with LPC/SPI.
> + * This is done by requesting HostOwnLPC register 
> + * (LPC_ISA_BRIDGE, write 1 in register 0x98).
> + * Then we have to read this register,
> + * and loop until we have the ownership.
> + * see doc AMD 44413 - AMD SP5100 Register Reference Guide.
> + */
> +static int resquest_lpc_ownership (void)
> +{
> +     uint8_t tmp;
> +     int i = 0;
> +
> +     if (lpc_isa_bridge == NULL)
> +             return 1;
> +
> +     pci_write_byte(lpc_isa_bridge, 0x98, 0x01);
> +
> +     while ((tmp = pci_read_byte (lpc_isa_bridge, 0x98)) == 0) {
> +             pci_write_byte(lpc_isa_bridge, 0x98, 0x01);
> +             if (++i > 1024) {
> +                     msg_perr("IMC did not release flash.\n");
> +                     return 1;
> +             }
> +
> +     }
> +     msg_pspew("flash ownership after %i cycles.\n", i);
> +     return 0;
> +}
> +
> +/*
> + * release LPC/SPI ownership (IMC can access to these resources)
> + * this is done by releasing HostOwnLPC register
> + * (write 0 in register 0x98)
> + */
> +static int release_lpc_ownership (void)
> +{
> +
> +     if (lpc_isa_bridge == NULL)
> +             return 1;
> +
> +     pci_write_byte(lpc_isa_bridge, 0x98, 0x00);
> +
> +     msg_pspew("flash ownership is released.\n");
> +     return 0;
> +}
> +
>  static void reset_internal_fifo_pointer(void)
>  {
>       mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
> @@ -93,6 +149,8 @@
>                     const unsigned char *writearr, unsigned char *readarr)
>  {
>       int count;
> +     int result = 0;
> +
>       /* First byte is cmd which can not being sent through FIFO. */
>       unsigned char cmd = *writearr++;
>       unsigned int readoffby1;
> @@ -103,16 +161,26 @@
>       msg_pspew("%s, cmd=%x, writecnt=%x, readcnt=%x\n",
>                 __func__, cmd, writecnt, readcnt);
>  
> +     if (resquest_lpc_ownership() != 0) {
> +             result = SPI_PROGRAMMER_ERROR;
> +             msg_pinfo("can't take ownership of LPC/SPI");
> +             goto return_status;
> +     }
> + 
> +
>       if (readcnt > 8) {
>               msg_pinfo("%s, SB600 SPI controller can not receive %d bytes, "
>                      "it is limited to 8 bytes\n", __func__, readcnt);
> -             return SPI_INVALID_LENGTH;
> +
> +             result = SPI_INVALID_LENGTH;
> +             goto return_status;
>       }
>  
>       if (writecnt > 8) {
>               msg_pinfo("%s, SB600 SPI controller can not send %d bytes, "
>                      "it is limited to 8 bytes\n", __func__, writecnt);
> -             return SPI_INVALID_LENGTH;
> +             result = SPI_INVALID_LENGTH;
> +             goto return_status;
>       }
>  
>       /* This is a workaround for a bug in SB600 and SB700. If we only send
> @@ -141,8 +209,10 @@
>        * We should send the data by sequence, which means we need to reset
>        * the FIFO pointer to the first byte we want to send.
>        */
> -     if (reset_compare_internal_fifo_pointer(writecnt))
> -             return SPI_PROGRAMMER_ERROR;
> +     if (reset_compare_internal_fifo_pointer(writecnt)) {
> +             result = SPI_PROGRAMMER_ERROR;
> +             goto return_status;
> +     }
>  
>       msg_pspew("Executing: \n");
>       execute_command();
> @@ -158,8 +228,10 @@
>        * the opcode, the FIFO already stores the response from the chip.
>        * Usually, the chip will respond with 0x00 or 0xff.
>        */
> -     if (reset_compare_internal_fifo_pointer(writecnt + readcnt))
> -             return SPI_PROGRAMMER_ERROR;
> +     if (reset_compare_internal_fifo_pointer(writecnt + readcnt)) {
> +             result = SPI_PROGRAMMER_ERROR;
> +             goto return_status;
> +     }
>  
>       /* Skip the bytes we sent. */
>       msg_pspew("Skipping: ");
> @@ -168,8 +240,10 @@
>               msg_pspew("[%02x]", cmd);
>       }
>       msg_pspew("\n");
> -     if (compare_internal_fifo_pointer(writecnt))
> -             return SPI_PROGRAMMER_ERROR;
> +     if (compare_internal_fifo_pointer(writecnt)) {
> +             result = SPI_PROGRAMMER_ERROR;
> +             goto return_status;
> +     }
>  
>       msg_pspew("Reading: ");
>       for (count = 0; count < readcnt; count++, readarr++) {
> @@ -177,8 +251,10 @@
>               msg_pspew("[%02x]", *readarr);
>       }
>       msg_pspew("\n");
> -     if (reset_compare_internal_fifo_pointer(readcnt + writecnt))
> -             return SPI_PROGRAMMER_ERROR;
> +     if (reset_compare_internal_fifo_pointer(readcnt + writecnt)) {
> +             result = SPI_PROGRAMMER_ERROR;
> +             goto return_status;
> +     }
>  
>       if (mmio_readb(sb600_spibar + 1) != readwrite) {
>               msg_perr("Unexpected change in SB600 read/write count!\n");
> @@ -186,10 +262,12 @@
>                        "causes random corruption.\nPlease stop all "
>                        "applications and drivers and IPMI which access the "
>                        "flash chip.\n");
> -             return SPI_PROGRAMMER_ERROR;
> +             result = SPI_PROGRAMMER_ERROR;
>       }
>  
> -     return 0;
> +return_status:
> +     release_lpc_ownership();
> +     return result;
>  }
>  
>  static const struct spi_programmer spi_programmer_sb600 = {
> @@ -211,6 +289,9 @@
>               "Reserved", "33", "22", "16.5"
>       };
>  
> +
> +     lpc_isa_bridge = dev;
> +
>       /* Read SPI_BaseAddr */
>       tmp = pci_read_long(dev, 0xa0);
>       tmp &= 0xffffffe0;      /* remove bits 4-0 (reserved) */

Acked-by: Thomas Gstaedtner <[email protected]>

I tested this patch (along with 2/2 of course) on live hardware (>10
reads, >10 erase/writes) and it works fine for me.
Tested on: Supermicro H8SCM-F-O, AMD SP5100

Please note, that I did no proper code review, I only tested, so let me
know if the "acked-by" sign-off should not be used here.
It did not seem like you used the Tested-by sign-off.

thomasg

_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to