diff options
Diffstat (limited to 'gpxe/src/drivers/net/phantom/phantom.c')
-rw-r--r-- | gpxe/src/drivers/net/phantom/phantom.c | 1499 |
1 files changed, 823 insertions, 676 deletions
diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c index 6c7d1fc9..33c76f62 100644 --- a/gpxe/src/drivers/net/phantom/phantom.c +++ b/gpxe/src/drivers/net/phantom/phantom.c @@ -25,12 +25,14 @@ #include <assert.h> #include <byteswap.h> #include <gpxe/pci.h> +#include <gpxe/io.h> #include <gpxe/malloc.h> #include <gpxe/iobuf.h> #include <gpxe/netdevice.h> #include <gpxe/if_ether.h> #include <gpxe/ethernet.h> #include <gpxe/spi.h> +#include <gpxe/settings.h> #include "phantom.h" /** @@ -40,11 +42,8 @@ * */ -/** Maximum time to wait for SPI lock */ -#define PHN_SPI_LOCK_TIMEOUT_MS 100 - -/** Maximum time to wait for SPI command to be issued */ -#define PHN_SPI_CMD_TIMEOUT_MS 100 +/** Maximum number of ports */ +#define PHN_MAX_NUM_PORTS 4 /** Maximum time to wait for command PEG to initialise * @@ -71,6 +70,9 @@ /** Maximum time to wait for test memory */ #define PHN_TEST_MEM_TIMEOUT_MS 100 +/** Maximum time to wait for CLP command to be issued */ +#define PHN_CLP_CMD_TIMEOUT_MS 500 + /** Link state poll frequency * * The link state will be checked once in every N calls to poll(). @@ -105,10 +107,41 @@ struct phantom_descriptor_rings { volatile uint32_t cmd_cons; }; -/** A Phantom NIC port */ -struct phantom_nic_port { - /** Phantom NIC containing this port */ - struct phantom_nic *phantom; +/** RX context creation request and response buffers */ +struct phantom_create_rx_ctx_rqrsp { + struct { + struct nx_hostrq_rx_ctx_s rx_ctx; + struct nx_hostrq_rds_ring_s rds; + struct nx_hostrq_sds_ring_s sds; + } __unm_dma_aligned hostrq; + struct { + struct nx_cardrsp_rx_ctx_s rx_ctx; + struct nx_cardrsp_rds_ring_s rds; + struct nx_cardrsp_sds_ring_s sds; + } __unm_dma_aligned cardrsp; +}; + +/** TX context creation request and response buffers */ +struct phantom_create_tx_ctx_rqrsp { + struct { + struct nx_hostrq_tx_ctx_s tx_ctx; + } __unm_dma_aligned hostrq; + struct { + struct nx_cardrsp_tx_ctx_s tx_ctx; + } __unm_dma_aligned cardrsp; +}; + +/** A Phantom NIC */ +struct phantom_nic { + /** BAR 0 */ + void *bar0; + /** Current CRB window */ + unsigned long crb_window; + /** CRB window access method */ + unsigned long ( *crb_access ) ( struct phantom_nic *phantom, + unsigned long reg ); + + /** Port number */ unsigned int port; @@ -143,73 +176,18 @@ struct phantom_nic_port { struct io_buffer *cds_iobuf[PHN_NUM_CDS]; - /** Link state poll timer */ - unsigned long link_poll_timer; - - /** Descriptor rings */ struct phantom_descriptor_rings *desc; -}; - -/** RX context creation request and response buffers */ -struct phantom_create_rx_ctx_rqrsp { - struct { - struct nx_hostrq_rx_ctx_s rx_ctx; - struct nx_hostrq_rds_ring_s rds; - struct nx_hostrq_sds_ring_s sds; - } __unm_dma_aligned hostrq; - struct { - struct nx_cardrsp_rx_ctx_s rx_ctx; - struct nx_cardrsp_rds_ring_s rds; - struct nx_cardrsp_sds_ring_s sds; - } __unm_dma_aligned cardrsp; -}; - -/** TX context creation request and response buffers */ -struct phantom_create_tx_ctx_rqrsp { - struct { - struct nx_hostrq_tx_ctx_s tx_ctx; - } __unm_dma_aligned hostrq; - struct { - struct nx_cardrsp_tx_ctx_s tx_ctx; - } __unm_dma_aligned cardrsp; -}; - -/** A Phantom DMA buffer area */ -union phantom_dma_buffer { - /** Dummy area required for (read-only) self-tests */ - uint8_t dummy_dma[UNM_DUMMY_DMA_SIZE]; - /** RX context creation request and response buffers */ - struct phantom_create_rx_ctx_rqrsp create_rx_ctx; - /** TX context creation request and response buffers */ - struct phantom_create_tx_ctx_rqrsp create_tx_ctx; -}; - -/** A Phantom NIC */ -struct phantom_nic { - /** BAR 0 */ - void *bar0; - /** Current CRB window */ - unsigned long crb_window; - /** CRB window access method */ - unsigned long ( *crb_access ) ( struct phantom_nic *phantom, - unsigned long reg ); - - /** Number of ports */ - int num_ports; - /** Per-port network devices */ - struct net_device *netdev[UNM_FLASH_NUM_PORTS]; - /** DMA buffers */ - union phantom_dma_buffer *dma_buf; - - /** Flash memory SPI bus */ - struct spi_bus spi_bus; - /** Flash memory SPI device */ - struct spi_device flash; /** Last known link state */ uint32_t link_state; + /** Link state poll timer */ + unsigned long link_poll_timer; + + + /** Non-volatile settings */ + struct settings settings; }; /*************************************************************************** @@ -227,21 +205,8 @@ struct phantom_nic { */ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window[] = { - [UNM_CRB_BLK_PCIE] = 0x0000000, - [UNM_CRB_BLK_CAM] = 0x2000000, - [UNM_CRB_BLK_ROMUSB] = 0x2000000, - [UNM_CRB_BLK_TEST] = 0x0000000, - }; - static const uint32_t reg_bases[] = { - [UNM_CRB_BLK_PCIE] = 0x6100000, - [UNM_CRB_BLK_CAM] = 0x6200000, - [UNM_CRB_BLK_ROMUSB] = 0x7300000, - [UNM_CRB_BLK_TEST] = 0x6200000, - }; - unsigned int block = UNM_CRB_BLK ( reg ); - unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = reg_window[block]; + unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) ); + uint32_t window = ( reg & 0x2000000 ); uint32_t verify_window; if ( phantom->crb_window != window ) { @@ -257,7 +222,7 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, phantom->crb_window = window; } - return ( reg_bases[block] + offset ); + return offset; } /** @@ -269,21 +234,8 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, */ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window[] = { - [UNM_CRB_BLK_PCIE] = 0x0000000, - [UNM_CRB_BLK_CAM] = 0x2000000, - [UNM_CRB_BLK_ROMUSB] = 0x2000000, - [UNM_CRB_BLK_TEST] = 0x0000000, - }; - static const uint32_t reg_bases[] = { - [UNM_CRB_BLK_PCIE] = 0x0100000, - [UNM_CRB_BLK_CAM] = 0x0200000, - [UNM_CRB_BLK_ROMUSB] = 0x1300000, - [UNM_CRB_BLK_TEST] = 0x0200000, - }; - unsigned int block = UNM_CRB_BLK ( reg ); - unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = reg_window[block]; + unsigned long offset = ( reg & 0x1ffffff ); + uint32_t window = ( reg & 0x2000000 ); uint32_t verify_window; if ( phantom->crb_window != window ) { @@ -299,7 +251,7 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, phantom->crb_window = window; } - return ( reg_bases[block] + offset ); + return offset; } /** @@ -311,31 +263,54 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, */ static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window_hi[] = { - [UNM_CRB_BLK_PCIE] = 0x77300000, - [UNM_CRB_BLK_CAM] = 0x41600000, - [UNM_CRB_BLK_ROMUSB] = 0x42100000, - [UNM_CRB_BLK_TEST] = 0x29500000, + static const struct { + uint8_t block; + uint16_t window_hi; + } reg_window_hi[] = { + { UNM_CRB_BLK_PCIE, 0x773 }, + { UNM_CRB_BLK_CAM, 0x416 }, + { UNM_CRB_BLK_ROMUSB, 0x421 }, + { UNM_CRB_BLK_TEST, 0x295 }, + { UNM_CRB_BLK_PEG_0, 0x340 }, + { UNM_CRB_BLK_PEG_1, 0x341 }, + { UNM_CRB_BLK_PEG_2, 0x342 }, + { UNM_CRB_BLK_PEG_3, 0x343 }, + { UNM_CRB_BLK_PEG_4, 0x34b }, }; unsigned int block = UNM_CRB_BLK ( reg ); unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = ( reg_window_hi[block] | ( offset & 0x000f0000 ) ); + uint32_t window; uint32_t verify_window; + unsigned int i; - if ( phantom->crb_window != window ) { + for ( i = 0 ; i < ( sizeof ( reg_window_hi ) / + sizeof ( reg_window_hi[0] ) ) ; i++ ) { - /* Write to the CRB window register */ - writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW ); + if ( reg_window_hi[i].block != block ) + continue; - /* Ensure that the write has reached the card */ - verify_window = readl ( phantom->bar0 + UNM_2M_CRB_WINDOW ); - assert ( verify_window == window ); + window = ( ( reg_window_hi[i].window_hi << 20 ) | + ( offset & 0x000f0000 ) ); - /* Record new window */ - phantom->crb_window = window; + if ( phantom->crb_window != window ) { + + /* Write to the CRB window register */ + writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW ); + + /* Ensure that the write has reached the card */ + verify_window = readl ( phantom->bar0 + + UNM_2M_CRB_WINDOW ); + assert ( verify_window == window ); + + /* Record new window */ + phantom->crb_window = window; + } + + return ( 0x1e0000 + ( offset & 0xffff ) ); } - return ( 0x1e0000 + ( offset & 0xffff ) ); + assert ( 0 ); + return 0; } /** @@ -401,8 +376,9 @@ static inline void phantom_write_hilo ( struct phantom_nic *phantom, * @v buf 8-byte buffer to fill * @ret rc Return status code */ -static int phantom_read_test_mem ( struct phantom_nic *phantom, - uint64_t offset, uint32_t buf[2] ) { +static int phantom_read_test_mem_block ( struct phantom_nic *phantom, + unsigned long offset, + uint32_t buf[2] ) { unsigned int retries; uint32_t test_control; @@ -429,28 +405,57 @@ static int phantom_read_test_mem ( struct phantom_nic *phantom, } /** + * Read single byte from Phantom test memory + * + * @v phantom Phantom NIC + * @v offset Offset within test memory + * @ret byte Byte read, or negative error + */ +static int phantom_read_test_mem ( struct phantom_nic *phantom, + unsigned long offset ) { + static union { + uint8_t bytes[8]; + uint32_t dwords[2]; + } cache; + static unsigned long cache_offset = -1UL; + unsigned long sub_offset; + int rc; + + sub_offset = ( offset & ( sizeof ( cache ) - 1 ) ); + offset = ( offset & ~( sizeof ( cache ) - 1 ) ); + + if ( cache_offset != offset ) { + if ( ( rc = phantom_read_test_mem_block ( phantom, offset, + cache.dwords )) !=0 ) + return rc; + cache_offset = offset; + } + + return cache.bytes[sub_offset]; +} + +/** * Dump Phantom firmware dmesg log * * @v phantom Phantom NIC * @v log Log number + * @v max_lines Maximum number of lines to show, or -1 to show all + * @ret rc Return status code */ -static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) { +static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log, + unsigned int max_lines ) { uint32_t head; uint32_t tail; uint32_t len; uint32_t sig; uint32_t offset; - union { - uint8_t bytes[8]; - uint32_t dwords[2]; - } buf; - unsigned int i; - int rc; + int byte; /* Optimise out for non-debug builds */ if ( ! DBG_LOG ) - return; + return 0; + /* Locate log */ head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) ); len = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_LEN ( log ) ); tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) ); @@ -463,165 +468,37 @@ static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) { sig, UNM_CAM_RAM_DMESG_SIG_MAGIC ); } - for ( offset = head ; offset < tail ; offset += 8 ) { - if ( ( rc = phantom_read_test_mem ( phantom, offset, - buf.dwords ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not read from test " - "memory: %s\n", phantom, strerror ( rc ) ); + /* Locate start of last (max_lines) lines */ + for ( offset = tail ; offset > head ; offset-- ) { + if ( ( byte = phantom_read_test_mem ( phantom, + ( offset - 1 ) ) ) < 0 ) + return byte; + if ( ( byte == '\n' ) && ( max_lines-- == 0 ) ) break; - } - for ( i = 0 ; ( ( i < sizeof ( buf ) ) && - ( offset + i ) < tail ) ; i++ ) { - DBG ( "%c", buf.bytes[i] ); - } + } + + /* Print lines */ + for ( ; offset < tail ; offset++ ) { + if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 ) + return byte; + DBG ( "%c", byte ); } DBG ( "\n" ); + return 0; } /** * Dump Phantom firmware dmesg logs * * @v phantom Phantom NIC + * @v max_lines Maximum number of lines to show, or -1 to show all */ static void __attribute__ (( unused )) -phantom_dmesg_all ( struct phantom_nic *phantom ) { +phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) { unsigned int i; for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ ) - phantom_dmesg ( phantom, i ); -} - -/*************************************************************************** - * - * SPI bus access (for flash memory) - * - */ - -/** - * Acquire Phantom SPI lock - * - * @v phantom Phantom NIC - * @ret rc Return status code - */ -static int phantom_spi_lock ( struct phantom_nic *phantom ) { - unsigned int retries; - uint32_t pcie_sem2_lock; - - for ( retries = 0 ; retries < PHN_SPI_LOCK_TIMEOUT_MS ; retries++ ) { - pcie_sem2_lock = phantom_readl ( phantom, UNM_PCIE_SEM2_LOCK ); - if ( pcie_sem2_lock != 0 ) - return 0; - mdelay ( 1 ); - } - - DBGC ( phantom, "Phantom %p timed out waiting for SPI lock\n", - phantom ); - return -ETIMEDOUT; -} - -/** - * Wait for Phantom SPI command to complete - * - * @v phantom Phantom NIC - * @ret rc Return status code - */ -static int phantom_spi_wait ( struct phantom_nic *phantom ) { - unsigned int retries; - uint32_t glb_status; - - for ( retries = 0 ; retries < PHN_SPI_CMD_TIMEOUT_MS ; retries++ ) { - glb_status = phantom_readl ( phantom, UNM_ROMUSB_GLB_STATUS ); - if ( glb_status & UNM_ROMUSB_GLB_STATUS_ROM_DONE ) - return 0; - mdelay ( 1 ); - } - - DBGC ( phantom, "Phantom %p timed out waiting for SPI command\n", - phantom ); - return -ETIMEDOUT; -} - -/** - * Release Phantom SPI lock - * - * @v phantom Phantom NIC - */ -static void phantom_spi_unlock ( struct phantom_nic *phantom ) { - phantom_readl ( phantom, UNM_PCIE_SEM2_UNLOCK ); -} - -/** - * Read/write data via Phantom SPI bus - * - * @v bus SPI bus - * @v device SPI device - * @v command Command - * @v address Address to read/write (<0 for no address) - * @v data_out TX data buffer (or NULL) - * @v data_in RX data buffer (or NULL) - * @v len Length of data buffer(s) - * @ret rc Return status code - */ -static int phantom_spi_rw ( struct spi_bus *bus, - struct spi_device *device, - unsigned int command, int address, - const void *data_out, void *data_in, - size_t len ) { - struct phantom_nic *phantom = - container_of ( bus, struct phantom_nic, spi_bus ); - uint32_t data; - int rc; - - DBGCP ( phantom, "Phantom %p SPI command %x at %x+%zx\n", - phantom, command, address, len ); - if ( data_out ) - DBGCP_HDA ( phantom, address, data_out, len ); - - /* We support only exactly 4-byte reads */ - if ( len != UNM_SPI_BLKSIZE ) { - DBGC ( phantom, "Phantom %p invalid SPI length %zx\n", - phantom, len ); - return -EINVAL; - } - - /* Acquire SPI lock */ - if ( ( rc = phantom_spi_lock ( phantom ) ) != 0 ) - goto err_lock; - - /* Issue SPI command as per the PRM */ - if ( data_out ) { - memcpy ( &data, data_out, sizeof ( data ) ); - phantom_writel ( phantom, data, UNM_ROMUSB_ROM_WDATA ); - } - phantom_writel ( phantom, address, UNM_ROMUSB_ROM_ADDRESS ); - phantom_writel ( phantom, ( device->address_len / 8 ), - UNM_ROMUSB_ROM_ABYTE_CNT ); - udelay ( 100 ); /* according to PRM */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT ); - phantom_writel ( phantom, command, UNM_ROMUSB_ROM_INSTR_OPCODE ); - - /* Wait for SPI command to complete */ - if ( ( rc = phantom_spi_wait ( phantom ) ) != 0 ) - goto err_wait; - - /* Reset address byte count and dummy byte count, because the - * PRM asks us to. - */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_ABYTE_CNT ); - udelay ( 100 ); /* according to PRM */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT ); - - /* Read data, if applicable */ - if ( data_in ) { - data = phantom_readl ( phantom, UNM_ROMUSB_ROM_RDATA ); - memcpy ( data_in, &data, sizeof ( data ) ); - DBGCP_HDA ( phantom, address, data_in, len ); - } - - err_wait: - phantom_spi_unlock ( phantom ); - err_lock: - return rc; + phantom_dmesg ( phantom, i, max_lines ); } /*************************************************************************** @@ -665,26 +542,24 @@ static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) { /** * Issue command to firmware * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v command Firmware command * @v arg1 Argument 1 * @v arg2 Argument 2 * @v arg3 Argument 3 * @ret rc Return status code */ -static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port, +static int phantom_issue_cmd ( struct phantom_nic *phantom, uint32_t command, uint32_t arg1, uint32_t arg2, uint32_t arg3 ) { - struct phantom_nic *phantom = phantom_port->phantom; uint32_t signature; int rc; /* Issue command */ - signature = NX_CDRP_SIGNATURE_MAKE ( phantom_port->port, + signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port, NXHAL_VERSION ); - DBGC2 ( phantom, "Phantom %p port %d issuing command %08lx (%08lx, " - "%08lx, %08lx)\n", phantom, phantom_port->port, - command, arg1, arg2, arg3 ); + DBGC2 ( phantom, "Phantom %p issuing command %08lx (%08lx, %08lx, " + "%08lx)\n", phantom, command, arg1, arg2, arg3 ); phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN ); phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 ); phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 ); @@ -705,36 +580,41 @@ static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port, /** * Issue buffer-format command to firmware * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v command Firmware command * @v buffer Buffer to pass to firmware * @v len Length of buffer * @ret rc Return status code */ -static int phantom_issue_buf_cmd ( struct phantom_nic_port *phantom_port, +static int phantom_issue_buf_cmd ( struct phantom_nic *phantom, uint32_t command, void *buffer, size_t len ) { uint64_t physaddr; physaddr = virt_to_bus ( buffer ); - return phantom_issue_cmd ( phantom_port, command, ( physaddr >> 32 ), + return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ), ( physaddr & 0xffffffffUL ), len ); } /** * Create Phantom RX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { struct phantom_create_rx_ctx_rqrsp *buf; int rc; + + /* Allocate context creation buffer */ + buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + if ( ! buf ) { + rc = -ENOMEM; + goto out; + } + memset ( buf, 0, sizeof ( *buf ) ); /* Prepare request */ - buf = &phantom->dma_buf->create_rx_ctx; - memset ( buf, 0, sizeof ( *buf ) ); buf->hostrq.rx_ctx.host_rsp_dma_addr = cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) ); buf->hostrq.rx_ctx.capabilities[0] = @@ -749,197 +629,194 @@ static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) { buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 ); buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 ); buf->hostrq.rds.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->rds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) ); buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE ); buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS ); buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL ); buf->hostrq.sds.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->sds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) ); buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS ); - DBGC ( phantom, "Phantom %p port %d creating RX context\n", - phantom, phantom_port->port ); + DBGC ( phantom, "Phantom %p creating RX context\n", phantom ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); /* Issue request */ - if ( ( rc = phantom_issue_buf_cmd ( phantom_port, + if ( ( rc = phantom_issue_buf_cmd ( phantom, NX_CDRP_CMD_CREATE_RX_CTX, &buf->hostrq, sizeof ( buf->hostrq ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not create RX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not create RX context: " + "%s\n", phantom, strerror ( rc ) ); DBGC ( phantom, "Request:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); DBGC ( phantom, "Response:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - return rc; + goto out; } /* Retrieve context parameters */ - phantom_port->rx_context_id = + phantom->rx_context_id = le16_to_cpu ( buf->cardrsp.rx_ctx.context_id ); - phantom_port->rds_producer_crb = + phantom->rds_producer_crb = ( UNM_CAM_RAM + le32_to_cpu ( buf->cardrsp.rds.host_producer_crb )); - phantom_port->sds_consumer_crb = + phantom->sds_consumer_crb = ( UNM_CAM_RAM + le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb )); - DBGC ( phantom, "Phantom %p port %d created RX context (id %04x, " - "port phys %02x virt %02x)\n", phantom, phantom_port->port, - phantom_port->rx_context_id, buf->cardrsp.rx_ctx.phys_port, - buf->cardrsp.rx_ctx.virt_port ); + DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys " + "%02x virt %02x)\n", phantom, phantom->rx_context_id, + buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - DBGC ( phantom, "Phantom %p port %d RDS producer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->rds_producer_crb ); - DBGC ( phantom, "Phantom %p port %d SDS consumer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->sds_consumer_crb ); + DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n", + phantom, phantom->rds_producer_crb ); + DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n", + phantom, phantom->sds_consumer_crb ); - return 0; + out: + free_dma ( buf, sizeof ( *buf ) ); + return rc; } /** * Destroy Phantom RX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static void phantom_destroy_rx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) { int rc; - DBGC ( phantom, "Phantom %p port %d destroying RX context (id %04x)\n", - phantom, phantom_port->port, phantom_port->rx_context_id ); + DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n", + phantom, phantom->rx_context_id ); /* Issue request */ - if ( ( rc = phantom_issue_cmd ( phantom_port, + if ( ( rc = phantom_issue_cmd ( phantom, NX_CDRP_CMD_DESTROY_RX_CTX, - phantom_port->rx_context_id, + phantom->rx_context_id, NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not destroy RX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not destroy RX context: " + "%s\n", phantom, strerror ( rc ) ); /* We're probably screwed */ return; } /* Clear context parameters */ - phantom_port->rx_context_id = 0; - phantom_port->rds_producer_crb = 0; - phantom_port->sds_consumer_crb = 0; + phantom->rx_context_id = 0; + phantom->rds_producer_crb = 0; + phantom->sds_consumer_crb = 0; /* Reset software counters */ - phantom_port->rds_producer_idx = 0; - phantom_port->rds_consumer_idx = 0; - phantom_port->sds_consumer_idx = 0; + phantom->rds_producer_idx = 0; + phantom->rds_consumer_idx = 0; + phantom->sds_consumer_idx = 0; } /** * Create Phantom TX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static int phantom_create_tx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { struct phantom_create_tx_ctx_rqrsp *buf; int rc; - /* Prepare request */ - buf = &phantom->dma_buf->create_tx_ctx; + /* Allocate context creation buffer */ + buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + if ( ! buf ) { + rc = -ENOMEM; + goto out; + } memset ( buf, 0, sizeof ( *buf ) ); + + /* Prepare request */ buf->hostrq.tx_ctx.host_rsp_dma_addr = cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) ); buf->hostrq.tx_ctx.cmd_cons_dma_addr = - cpu_to_le64 ( virt_to_bus ( &phantom_port->desc->cmd_cons ) ); - buf->hostrq.tx_ctx.dummy_dma_addr = - cpu_to_le64 ( virt_to_bus ( phantom->dma_buf->dummy_dma ) ); + cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) ); buf->hostrq.tx_ctx.capabilities[0] = cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN ); buf->hostrq.tx_ctx.host_int_crb_mode = cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED ); buf->hostrq.tx_ctx.cds_ring.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->cds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) ); buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS ); - DBGC ( phantom, "Phantom %p port %d creating TX context\n", - phantom, phantom_port->port ); + DBGC ( phantom, "Phantom %p creating TX context\n", phantom ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); /* Issue request */ - if ( ( rc = phantom_issue_buf_cmd ( phantom_port, + if ( ( rc = phantom_issue_buf_cmd ( phantom, NX_CDRP_CMD_CREATE_TX_CTX, &buf->hostrq, sizeof ( buf->hostrq ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not create TX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not create TX context: " + "%s\n", phantom, strerror ( rc ) ); DBGC ( phantom, "Request:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); DBGC ( phantom, "Response:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - return rc; + goto out; } /* Retrieve context parameters */ - phantom_port->tx_context_id = + phantom->tx_context_id = le16_to_cpu ( buf->cardrsp.tx_ctx.context_id ); - phantom_port->cds_producer_crb = + phantom->cds_producer_crb = ( UNM_CAM_RAM + le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb)); - DBGC ( phantom, "Phantom %p port %d created TX context (id %04x, " - "port phys %02x virt %02x)\n", phantom, phantom_port->port, - phantom_port->tx_context_id, buf->cardrsp.tx_ctx.phys_port, - buf->cardrsp.tx_ctx.virt_port ); + DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys " + "%02x virt %02x)\n", phantom, phantom->tx_context_id, + buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - DBGC ( phantom, "Phantom %p port %d CDS producer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->cds_producer_crb ); + DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n", + phantom, phantom->cds_producer_crb ); - return 0; + out: + free_dma ( buf, sizeof ( *buf ) ); + return rc; } /** * Destroy Phantom TX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) { int rc; - DBGC ( phantom, "Phantom %p port %d destroying TX context (id %04x)\n", - phantom, phantom_port->port, phantom_port->tx_context_id ); + DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n", + phantom, phantom->tx_context_id ); /* Issue request */ - if ( ( rc = phantom_issue_cmd ( phantom_port, + if ( ( rc = phantom_issue_cmd ( phantom, NX_CDRP_CMD_DESTROY_TX_CTX, - phantom_port->tx_context_id, + phantom->tx_context_id, NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not destroy TX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not destroy TX context: " + "%s\n", phantom, strerror ( rc ) ); /* We're probably screwed */ return; } /* Clear context parameters */ - phantom_port->tx_context_id = 0; - phantom_port->cds_producer_crb = 0; + phantom->tx_context_id = 0; + phantom->cds_producer_crb = 0; /* Reset software counters */ - phantom_port->cds_producer_idx = 0; - phantom_port->cds_consumer_idx = 0; + phantom->cds_producer_idx = 0; + phantom->cds_consumer_idx = 0; } /*************************************************************************** @@ -951,11 +828,10 @@ static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) { /** * Allocate Phantom RX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret index RX descriptor index, or negative error */ -static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_alloc_rds ( struct phantom_nic *phantom ) { unsigned int rds_producer_idx; unsigned int next_rds_producer_idx; @@ -965,12 +841,11 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { * guaranteed never to be an overestimate of the number of * descriptors read by the hardware. */ - rds_producer_idx = phantom_port->rds_producer_idx; + rds_producer_idx = phantom->rds_producer_idx; next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS ); - if ( next_rds_producer_idx == phantom_port->rds_consumer_idx ) { - DBGC ( phantom, "Phantom %p port %d RDS ring full (index %d " - "not consumed)\n", phantom, phantom_port->port, - next_rds_producer_idx ); + if ( next_rds_producer_idx == phantom->rds_consumer_idx ) { + DBGC ( phantom, "Phantom %p RDS ring full (index %d not " + "consumed)\n", phantom, next_rds_producer_idx ); return -ENOBUFS; } @@ -980,41 +855,38 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { /** * Post Phantom RX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v rds RX descriptor */ -static void phantom_post_rds ( struct phantom_nic_port *phantom_port, +static void phantom_post_rds ( struct phantom_nic *phantom, struct phantom_rds *rds ) { - struct phantom_nic *phantom = phantom_port->phantom; unsigned int rds_producer_idx; unsigned int next_rds_producer_idx; struct phantom_rds *entry; /* Copy descriptor to ring */ - rds_producer_idx = phantom_port->rds_producer_idx; - entry = &phantom_port->desc->rds[rds_producer_idx]; + rds_producer_idx = phantom->rds_producer_idx; + entry = &phantom->desc->rds[rds_producer_idx]; memcpy ( entry, rds, sizeof ( *entry ) ); - DBGC2 ( phantom, "Phantom %p port %d posting RDS %ld (slot %d):\n", - phantom, phantom_port->port, NX_GET ( rds, handle ), - rds_producer_idx ); + DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n", + phantom, NX_GET ( rds, handle ), rds_producer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) ); /* Update producer index */ next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS ); - phantom_port->rds_producer_idx = next_rds_producer_idx; + phantom->rds_producer_idx = next_rds_producer_idx; wmb(); - phantom_writel ( phantom, phantom_port->rds_producer_idx, - phantom_port->rds_producer_crb ); + phantom_writel ( phantom, phantom->rds_producer_idx, + phantom->rds_producer_crb ); } /** * Allocate Phantom TX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret index TX descriptor index, or negative error */ -static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_alloc_cds ( struct phantom_nic *phantom ) { unsigned int cds_producer_idx; unsigned int next_cds_producer_idx; @@ -1022,12 +894,11 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { * in strict order, so we just check for a collision against * the consumer index. */ - cds_producer_idx = phantom_port->cds_producer_idx; + cds_producer_idx = phantom->cds_producer_idx; next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS ); - if ( next_cds_producer_idx == phantom_port->cds_consumer_idx ) { - DBGC ( phantom, "Phantom %p port %d CDS ring full (index %d " - "not consumed)\n", phantom, phantom_port->port, - next_cds_producer_idx ); + if ( next_cds_producer_idx == phantom->cds_consumer_idx ) { + DBGC ( phantom, "Phantom %p CDS ring full (index %d not " + "consumed)\n", phantom, next_cds_producer_idx ); return -ENOBUFS; } @@ -1037,30 +908,29 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { /** * Post Phantom TX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v cds TX descriptor */ -static void phantom_post_cds ( struct phantom_nic_port *phantom_port, +static void phantom_post_cds ( struct phantom_nic *phantom, union phantom_cds *cds ) { - struct phantom_nic *phantom = phantom_port->phantom; unsigned int cds_producer_idx; unsigned int next_cds_producer_idx; union phantom_cds *entry; /* Copy descriptor to ring */ - cds_producer_idx = phantom_port->cds_producer_idx; - entry = &phantom_port->desc->cds[cds_producer_idx]; + cds_producer_idx = phantom->cds_producer_idx; + entry = &phantom->desc->cds[cds_producer_idx]; memcpy ( entry, cds, sizeof ( *entry ) ); - DBGC2 ( phantom, "Phantom %p port %d posting CDS %d:\n", - phantom, phantom_port->port, cds_producer_idx ); + DBGC2 ( phantom, "Phantom %p posting CDS %d:\n", + phantom, cds_producer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) ); /* Update producer index */ next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS ); - phantom_port->cds_producer_idx = next_cds_producer_idx; + phantom->cds_producer_idx = next_cds_producer_idx; wmb(); - phantom_writel ( phantom, phantom_port->cds_producer_idx, - phantom_port->cds_producer_crb ); + phantom_writel ( phantom, phantom->cds_producer_idx, + phantom->cds_producer_crb ); } /*************************************************************************** @@ -1072,19 +942,19 @@ static void phantom_post_cds ( struct phantom_nic_port *phantom_port, /** * Add/remove MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @v opcode MAC request opcode * @ret rc Return status code */ -static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, +static int phantom_update_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr, unsigned int opcode ) { union phantom_cds cds; int index; /* Get descriptor ring entry */ - index = phantom_alloc_cds ( phantom_port ); + index = phantom_alloc_cds ( phantom ); if ( index < 0 ) return index; @@ -1094,7 +964,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, nic_request.common.opcode, UNM_NIC_REQUEST ); NX_FILL_2 ( &cds, 1, nic_request.header.opcode, UNM_MAC_EVENT, - nic_request.header.context_id, phantom_port->port ); + nic_request.header.context_id, phantom->port ); NX_FILL_7 ( &cds, 2, nic_request.body.mac_request.opcode, opcode, nic_request.body.mac_request.mac_addr_0, ll_addr[0], @@ -1105,7 +975,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, nic_request.body.mac_request.mac_addr_5, ll_addr[5] ); /* Post descriptor */ - phantom_post_cds ( phantom_port, &cds ); + phantom_post_cds ( phantom, &cds ); return 0; } @@ -1113,35 +983,33 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, /** * Add MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @ret rc Return status code */ -static inline int phantom_add_macaddr ( struct phantom_nic_port *phantom_port, +static inline int phantom_add_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; - DBGC ( phantom, "Phantom %p port %d adding MAC address %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p adding MAC address %s\n", + phantom, eth_ntoa ( ll_addr ) ); - return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_ADD ); + return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD ); } /** * Remove MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @ret rc Return status code */ -static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port, +static inline int phantom_del_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; - DBGC ( phantom, "Phantom %p port %d removing MAC address %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p removing MAC address %s\n", + phantom, eth_ntoa ( ll_addr ) ); - return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_DEL ); + return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL ); } /*************************************************************************** @@ -1153,14 +1021,12 @@ static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port, /** * Poll link state * - * @v phantom Phantom NIC + * @v netdev Network device */ -static void phantom_poll_link_state ( struct phantom_nic *phantom ) { - struct net_device *netdev; - struct phantom_nic_port *phantom_port; +static void phantom_poll_link_state ( struct net_device *netdev ) { + struct phantom_nic *phantom = netdev_priv ( netdev ); uint32_t xg_state_p3; unsigned int link; - int i; /* Read link state */ xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 ); @@ -1174,28 +1040,22 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) { phantom, xg_state_p3, phantom->link_state ); phantom->link_state = xg_state_p3; - /* Indicate per-port link state to gPXE */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - netdev = phantom->netdev[i]; - phantom_port = netdev_priv ( netdev ); - link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom_port->port, - phantom->link_state ); - switch ( link ) { - case UNM_NIC_REG_XG_STATE_P3_LINK_UP: - DBGC ( phantom, "Phantom %p port %d link is up\n", - phantom, phantom_port->port ); - netdev_link_up ( netdev ); - break; - case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN: - DBGC ( phantom, "Phantom %p port %d link is down\n", - phantom, phantom_port->port ); - netdev_link_down ( netdev ); - break; - default: - DBGC ( phantom, "Phantom %p port %d bad link state " - "%d\n", phantom, phantom_port->port, link ); - break; - } + /* Indicate link state to gPXE */ + link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port, + phantom->link_state ); + switch ( link ) { + case UNM_NIC_REG_XG_STATE_P3_LINK_UP: + DBGC ( phantom, "Phantom %p link is up\n", phantom ); + netdev_link_up ( netdev ); + break; + case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN: + DBGC ( phantom, "Phantom %p link is down\n", phantom ); + netdev_link_down ( netdev ); + break; + default: + DBGC ( phantom, "Phantom %p bad link state %d\n", + phantom, link ); + break; } } @@ -1211,7 +1071,7 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) { * @v netdev Net device */ static void phantom_refill_rx_ring ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; struct phantom_rds rds; unsigned int handle; @@ -1222,11 +1082,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { /* Skip this index if the descriptor has not yet been * consumed. */ - if ( phantom_port->rds_iobuf[handle] != NULL ) + if ( phantom->rds_iobuf[handle] != NULL ) continue; /* Allocate descriptor ring entry */ - index = phantom_alloc_rds ( phantom_port ); + index = phantom_alloc_rds ( phantom ); assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS ); assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */ @@ -1247,11 +1107,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { dma_addr, virt_to_bus ( iobuf->data ) ); /* Record I/O buffer */ - assert ( phantom_port->rds_iobuf[handle] == NULL ); - phantom_port->rds_iobuf[handle] = iobuf; + assert ( phantom->rds_iobuf[handle] == NULL ); + phantom->rds_iobuf[handle] = iobuf; /* Post descriptor */ - phantom_post_rds ( phantom_port, &rds ); + phantom_post_rds ( phantom, &rds ); } } @@ -1262,24 +1122,24 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { * @ret rc Return status code */ static int phantom_open ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); int rc; /* Allocate and zero descriptor rings */ - phantom_port->desc = malloc_dma ( sizeof ( *(phantom_port->desc) ), + phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ), UNM_DMA_BUFFER_ALIGN ); - if ( ! phantom_port->desc ) { + if ( ! phantom->desc ) { rc = -ENOMEM; goto err_alloc_desc; } - memset ( phantom_port->desc, 0, sizeof ( *(phantom_port->desc) ) ); + memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) ); /* Create RX context */ - if ( ( rc = phantom_create_rx_ctx ( phantom_port ) ) != 0 ) + if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 ) goto err_create_rx_ctx; /* Create TX context */ - if ( ( rc = phantom_create_tx_ctx ( phantom_port ) ) != 0 ) + if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 ) goto err_create_tx_ctx; /* Fill the RX descriptor ring */ @@ -1293,26 +1153,26 @@ static int phantom_open ( struct net_device *netdev ) { * packets (or, failing that, promiscuous mode), but the * firmware doesn't currently support this. */ - if ( ( rc = phantom_add_macaddr ( phantom_port, + if ( ( rc = phantom_add_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ) ) != 0 ) goto err_add_macaddr_broadcast; - if ( ( rc = phantom_add_macaddr ( phantom_port, + if ( ( rc = phantom_add_macaddr ( phantom, netdev->ll_addr ) ) != 0 ) goto err_add_macaddr_unicast; return 0; - phantom_del_macaddr ( phantom_port, netdev->ll_addr ); + phantom_del_macaddr ( phantom, netdev->ll_addr ); err_add_macaddr_unicast: - phantom_del_macaddr ( phantom_port, + phantom_del_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ); err_add_macaddr_broadcast: - phantom_destroy_tx_ctx ( phantom_port ); + phantom_destroy_tx_ctx ( phantom ); err_create_tx_ctx: - phantom_destroy_rx_ctx ( phantom_port ); + phantom_destroy_rx_ctx ( phantom ); err_create_rx_ctx: - free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) ); - phantom_port->desc = NULL; + free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + phantom->desc = NULL; err_alloc_desc: return rc; } @@ -1323,32 +1183,32 @@ static int phantom_open ( struct net_device *netdev ) { * @v netdev Net device */ static void phantom_close ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; unsigned int i; /* Shut down the port */ - phantom_del_macaddr ( phantom_port, netdev->ll_addr ); - phantom_del_macaddr ( phantom_port, + phantom_del_macaddr ( phantom, netdev->ll_addr ); + phantom_del_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ); - phantom_destroy_tx_ctx ( phantom_port ); - phantom_destroy_rx_ctx ( phantom_port ); - free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) ); - phantom_port->desc = NULL; + phantom_destroy_tx_ctx ( phantom ); + phantom_destroy_rx_ctx ( phantom ); + free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + phantom->desc = NULL; /* Flush any uncompleted descriptors */ for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) { - iobuf = phantom_port->rds_iobuf[i]; + iobuf = phantom->rds_iobuf[i]; if ( iobuf ) { free_iob ( iobuf ); - phantom_port->rds_iobuf[i] = NULL; + phantom->rds_iobuf[i] = NULL; } } for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) { - iobuf = phantom_port->cds_iobuf[i]; + iobuf = phantom->cds_iobuf[i]; if ( iobuf ) { netdev_tx_complete_err ( netdev, iobuf, -ECANCELED ); - phantom_port->cds_iobuf[i] = NULL; + phantom->cds_iobuf[i] = NULL; } } } @@ -1362,12 +1222,12 @@ static void phantom_close ( struct net_device *netdev ) { */ static int phantom_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); union phantom_cds cds; int index; /* Get descriptor ring entry */ - index = phantom_alloc_cds ( phantom_port ); + index = phantom_alloc_cds ( phantom ); if ( index < 0 ) return index; @@ -1378,19 +1238,19 @@ static int phantom_transmit ( struct net_device *netdev, tx.num_buffers, 1, tx.length, iob_len ( iobuf ) ); NX_FILL_2 ( &cds, 2, - tx.port, phantom_port->port, - tx.context_id, phantom_port->port ); + tx.port, phantom->port, + tx.context_id, phantom->port ); NX_FILL_1 ( &cds, 4, tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) ); NX_FILL_1 ( &cds, 5, tx.buffer1_length, iob_len ( iobuf ) ); /* Record I/O buffer */ - assert ( phantom_port->cds_iobuf[index] == NULL ); - phantom_port->cds_iobuf[index] = iobuf; + assert ( phantom->cds_iobuf[index] == NULL ); + phantom->cds_iobuf[index] = iobuf; /* Post descriptor */ - phantom_post_cds ( phantom_port, &cds ); + phantom_post_cds ( phantom, &cds ); return 0; } @@ -1401,8 +1261,7 @@ static int phantom_transmit ( struct net_device *netdev, * @v netdev Network device */ static void phantom_poll ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); - struct phantom_nic *phantom = phantom_port->phantom; + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; unsigned int cds_consumer_idx; unsigned int raw_new_cds_consumer_idx; @@ -1414,33 +1273,33 @@ static void phantom_poll ( struct net_device *netdev ) { unsigned int sds_opcode; /* Check for TX completions */ - cds_consumer_idx = phantom_port->cds_consumer_idx; - raw_new_cds_consumer_idx = phantom_port->desc->cmd_cons; + cds_consumer_idx = phantom->cds_consumer_idx; + raw_new_cds_consumer_idx = phantom->desc->cmd_cons; new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx ); while ( cds_consumer_idx != new_cds_consumer_idx ) { - DBGC2 ( phantom, "Phantom %p port %d CDS %d complete\n", - phantom, phantom_port->port, cds_consumer_idx ); + DBGC2 ( phantom, "Phantom %p CDS %d complete\n", + phantom, cds_consumer_idx ); /* Completions may be for commands other than TX, so * there may not always be an associated I/O buffer. */ - if ( ( iobuf = phantom_port->cds_iobuf[cds_consumer_idx] ) ) { + if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) { netdev_tx_complete ( netdev, iobuf ); - phantom_port->cds_iobuf[cds_consumer_idx] = NULL; + phantom->cds_iobuf[cds_consumer_idx] = NULL; } cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS ); - phantom_port->cds_consumer_idx = cds_consumer_idx; + phantom->cds_consumer_idx = cds_consumer_idx; } /* Check for received packets */ - rds_consumer_idx = phantom_port->rds_consumer_idx; - sds_consumer_idx = phantom_port->sds_consumer_idx; + rds_consumer_idx = phantom->rds_consumer_idx; + sds_consumer_idx = phantom->sds_consumer_idx; while ( 1 ) { - sds = &phantom_port->desc->sds[sds_consumer_idx]; + sds = &phantom->desc->sds[sds_consumer_idx]; if ( NX_GET ( sds, owner ) == 0 ) break; - DBGC2 ( phantom, "Phantom %p port %d SDS %d status:\n", - phantom, phantom_port->port, sds_consumer_idx ); + DBGC2 ( phantom, "Phantom %p SDS %d status:\n", + phantom, sds_consumer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) ); /* Check received opcode */ @@ -1452,24 +1311,23 @@ static void phantom_poll ( struct net_device *netdev ) { * descriptor has been written. */ if ( NX_GET ( sds, total_length ) == 0 ) { - DBGC ( phantom, "Phantom %p port %d SDS %d " - "incomplete; deferring\n", phantom, - phantom_port->port, sds_consumer_idx ); + DBGC ( phantom, "Phantom %p SDS %d " + "incomplete; deferring\n", + phantom, sds_consumer_idx ); /* Leave for next poll() */ break; } /* Process received packet */ sds_handle = NX_GET ( sds, handle ); - iobuf = phantom_port->rds_iobuf[sds_handle]; + iobuf = phantom->rds_iobuf[sds_handle]; assert ( iobuf != NULL ); iob_put ( iobuf, NX_GET ( sds, total_length ) ); iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) ); - DBGC2 ( phantom, "Phantom %p port %d RDS %d " - "complete\n", - phantom, phantom_port->port, sds_handle ); + DBGC2 ( phantom, "Phantom %p RDS %d complete\n", + phantom, sds_handle ); netdev_rx ( netdev, iobuf ); - phantom_port->rds_iobuf[sds_handle] = NULL; + phantom->rds_iobuf[sds_handle] = NULL; /* Update RDS consumer counter. This is a * lower bound for the number of descriptors @@ -1480,13 +1338,12 @@ static void phantom_poll ( struct net_device *netdev ) { */ rds_consumer_idx = ( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS ); - phantom_port->rds_consumer_idx = rds_consumer_idx; + phantom->rds_consumer_idx = rds_consumer_idx; } else { - DBGC ( phantom, "Phantom %p port %d unexpected SDS " - "opcode %02x\n", - phantom, phantom_port->port, sds_opcode ); + DBGC ( phantom, "Phantom %p unexpected SDS opcode " + "%02x\n", phantom, sds_opcode ); DBGC_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof ( *sds ) ); } @@ -1496,20 +1353,20 @@ static void phantom_poll ( struct net_device *netdev ) { /* Update SDS consumer index */ sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS ); - phantom_port->sds_consumer_idx = sds_consumer_idx; + phantom->sds_consumer_idx = sds_consumer_idx; wmb(); - phantom_writel ( phantom, phantom_port->sds_consumer_idx, - phantom_port->sds_consumer_crb ); + phantom_writel ( phantom, phantom->sds_consumer_idx, + phantom->sds_consumer_crb ); } /* Refill the RX descriptor ring */ phantom_refill_rx_ring ( netdev ); /* Occasionally poll the link state */ - if ( phantom_port->link_poll_timer-- == 0 ) { - phantom_poll_link_state ( phantom ); + if ( phantom->link_poll_timer-- == 0 ) { + phantom_poll_link_state ( netdev ); /* Reset the link poll timer */ - phantom_port->link_poll_timer = PHN_LINK_POLL_FREQUENCY; + phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY; } } @@ -1520,9 +1377,8 @@ static void phantom_poll ( struct net_device *netdev ) { * @v enable Interrupts should be enabled */ static void phantom_irq ( struct net_device *netdev, int enable ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); - struct phantom_nic *phantom = phantom_port->phantom; - static const unsigned long sw_int_mask_reg[UNM_FLASH_NUM_PORTS] = { + struct phantom_nic *phantom = netdev_priv ( netdev ); + static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = { UNM_NIC_REG_SW_INT_MASK_0, UNM_NIC_REG_SW_INT_MASK_1, UNM_NIC_REG_SW_INT_MASK_2, @@ -1531,7 +1387,7 @@ static void phantom_irq ( struct net_device *netdev, int enable ) { phantom_writel ( phantom, ( enable ? 1 : 0 ), - sw_int_mask_reg[phantom_port->port] ); + sw_int_mask_reg[phantom->port] ); } /** Phantom net device operations */ @@ -1543,6 +1399,336 @@ static struct net_device_operations phantom_operations = { .irq = phantom_irq, }; +/*************************************************************************** + * + * CLP settings + * + */ + +/** Phantom CLP settings tag magic */ +#define PHN_CLP_TAG_MAGIC 0xc19c1900UL + +/** Phantom CLP settings tag magic mask */ +#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL + +/** Phantom CLP data + * + */ +union phantom_clp_data { + /** Data bytes + * + * This field is right-aligned; if only N bytes are present + * then bytes[0]..bytes[7-N] should be zero, and the data + * should be in bytes[7-N+1] to bytes[7]; + */ + uint8_t bytes[8]; + /** Dwords for the CLP interface */ + struct { + /** High dword, in network byte order */ + uint32_t hi; + /** Low dword, in network byte order */ + uint32_t lo; + } dwords; +}; +#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) ) + +/** + * Wait for Phantom CLP command to complete + * + * @v phantom Phantom NIC + * @ret rc Return status code + */ +static int phantom_clp_wait ( struct phantom_nic *phantom ) { + unsigned int retries; + uint32_t status; + + for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) { + status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS ); + if ( status & UNM_CAM_RAM_CLP_STATUS_DONE ) + return 0; + mdelay ( 1 ); + } + + DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n", + phantom ); + return -ETIMEDOUT; +} + +/** + * Issue Phantom CLP command + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v opcode Opcode + * @v data_in Data in, or NULL + * @v data_out Data out, or NULL + * @v offset Offset within data + * @v len Data buffer length + * @ret len Total transfer length (for reads), or negative error + */ +static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port, + unsigned int opcode, const void *data_in, + void *data_out, size_t offset, size_t len ) { + union phantom_clp_data data; + unsigned int index = ( offset / sizeof ( data ) ); + unsigned int last = 0; + size_t in_frag_len; + uint8_t *in_frag; + uint32_t command; + uint32_t status; + size_t read_len; + unsigned int error; + size_t out_frag_len; + uint8_t *out_frag; + int rc; + + /* Sanity checks */ + assert ( ( offset % sizeof ( data ) ) == 0 ); + if ( len > 255 ) { + DBGC ( phantom, "Phantom %p invalid CLP length %zd\n", + phantom, len ); + return -EINVAL; + } + + /* Check that CLP interface is ready */ + if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 ) + return rc; + + /* Copy data in */ + memset ( &data, 0, sizeof ( data ) ); + if ( data_in ) { + assert ( offset < len ); + in_frag_len = ( len - offset ); + if ( in_frag_len > sizeof ( data ) ) { + in_frag_len = sizeof ( data ); + } else { + last = 1; + } + in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ]; + memcpy ( in_frag, ( data_in + offset ), in_frag_len ); + phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ), + UNM_CAM_RAM_CLP_DATA_LO ); + phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ), + UNM_CAM_RAM_CLP_DATA_HI ); + } + + /* Issue CLP command */ + command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) | + ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) ); + phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND ); + mb(); + phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START, + UNM_CAM_RAM_CLP_STATUS ); + + /* Wait for command to complete */ + if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 ) + return rc; + + /* Get command status */ + status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS ); + read_len = ( ( status >> 16 ) & 0xff ); + error = ( ( status >> 8 ) & 0xff ); + if ( error ) { + DBGC ( phantom, "Phantom %p CLP command error %02x\n", + phantom, error ); + return -EIO; + } + + /* Copy data out */ + if ( data_out ) { + data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom, + UNM_CAM_RAM_CLP_DATA_LO ) ); + data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom, + UNM_CAM_RAM_CLP_DATA_HI ) ); + out_frag_len = ( read_len - offset ); + if ( out_frag_len > sizeof ( data ) ) + out_frag_len = sizeof ( data ); + out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ]; + if ( out_frag_len > ( len - offset ) ) + out_frag_len = ( len - offset ); + memcpy ( ( data_out + offset ), out_frag, out_frag_len ); + } + + return read_len; +} + +/** + * Store Phantom CLP setting + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v setting Setting number + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port, + unsigned int setting, const void *data, + size_t len ) { + unsigned int opcode = setting; + size_t offset; + int rc; + + for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) { + if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data, + NULL, offset, len ) ) < 0 ) + return rc; + } + return 0; +} + +/** + * Fetch Phantom CLP setting + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v setting Setting number + * @v data Data buffer + * @v len Length of data buffer + * @ret len Length of setting, or negative error + */ +static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port, + unsigned int setting, void *data, size_t len ) { + unsigned int opcode = ( setting + 1 ); + size_t offset = 0; + int read_len; + + while ( 1 ) { + read_len = phantom_clp_cmd ( phantom, port, opcode, NULL, + data, offset, len ); + if ( read_len < 0 ) + return read_len; + offset += PHN_CLP_BLKSIZE; + if ( offset >= ( unsigned ) read_len ) + break; + if ( offset >= len ) + break; + } + return read_len; +} + +/** A Phantom CLP setting */ +struct phantom_clp_setting { + /** gPXE setting */ + struct setting *setting; + /** Setting number */ + unsigned int clp_setting; +}; + +/** Phantom CLP settings */ +static struct phantom_clp_setting clp_settings[] = { + { &mac_setting, 0x01 }, +}; + +/** + * Find Phantom CLP setting + * + * @v setting gPXE setting + * @v clp_setting Setting number, or 0 if not found + */ +static unsigned int +phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) { + struct phantom_clp_setting *clp_setting; + unsigned int i; + + /* Search the list of explicitly-defined settings */ + for ( i = 0 ; i < ( sizeof ( clp_settings ) / + sizeof ( clp_settings[0] ) ) ; i++ ) { + clp_setting = &clp_settings[i]; + if ( setting_cmp ( setting, clp_setting->setting ) == 0 ) + return clp_setting->clp_setting; + } + + /* Allow for use of numbered settings */ + if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC ) + return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK ); + + DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n", + phantom, setting->name ); + + return 0; +} + +/** + * Store Phantom CLP setting + * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int phantom_store_setting ( struct settings *settings, + struct setting *setting, + const void *data, size_t len ) { + struct phantom_nic *phantom = + container_of ( settings, struct phantom_nic, settings ); + unsigned int clp_setting; + int rc; + + /* Find Phantom setting equivalent to gPXE setting */ + clp_setting = phantom_clp_setting ( phantom, setting ); + if ( ! clp_setting ) + return -ENOTSUP; + + /* Store setting */ + if ( ( rc = phantom_clp_store ( phantom, phantom->port, + clp_setting, data, len ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not store setting \"%s\": " + "%s\n", phantom, setting->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Fetch Phantom CLP setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int phantom_fetch_setting ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct phantom_nic *phantom = + container_of ( settings, struct phantom_nic, settings ); + unsigned int clp_setting; + int read_len; + int rc; + + /* Find Phantom setting equivalent to gPXE setting */ + clp_setting = phantom_clp_setting ( phantom, setting ); + if ( ! clp_setting ) + return -ENOTSUP; + + /* Fetch setting */ + if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port, + clp_setting, data, len ) ) < 0 ){ + rc = read_len; + DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": " + "%s\n", phantom, setting->name, strerror ( rc ) ); + return rc; + } + + return read_len; +} + +/** Phantom CLP settings operations */ +static struct settings_operations phantom_settings_operations = { + .store = phantom_store_setting, + .fetch = phantom_fetch_setting, +}; + +/*************************************************************************** + * + * Initialisation + * + */ + /** * Map Phantom CRB window * @@ -1556,8 +1742,15 @@ static int phantom_map_crb ( struct phantom_nic *phantom, bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 ); bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 ); - DBGC ( phantom, "Phantom %p BAR0 is %08lx+%lx\n", - phantom, bar0_start, bar0_size ); + DBGC ( phantom, "Phantom %p is PCI %02x:%02x.%x with BAR0 at " + "%08lx+%lx\n", phantom, pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), bar0_start, bar0_size ); + + if ( ! bar0_start ) { + DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n", + phantom ); + return -EINVAL; + } switch ( bar0_size ) { case ( 128 * 1024 * 1024 ) : @@ -1592,71 +1785,23 @@ static int phantom_map_crb ( struct phantom_nic *phantom, } /** - * Read Phantom flash contents + * Unhalt all PEGs * * @v phantom Phantom NIC - * @ret rc Return status code */ -static int phantom_read_flash ( struct phantom_nic *phantom ) { - struct unm_board_info board_info; - int rc; - - /* Initialise flash access */ - phantom->spi_bus.rw = phantom_spi_rw; - phantom->flash.bus = &phantom->spi_bus; - init_m25p32 ( &phantom->flash ); - /* Phantom doesn't support greater than 4-byte block sizes */ - phantom->flash.nvs.block_size = UNM_SPI_BLKSIZE; - - /* Read and verify board information */ - if ( ( rc = nvs_read ( &phantom->flash.nvs, UNM_BRDCFG_START, - &board_info, sizeof ( board_info ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not read board info: %s\n", - phantom, strerror ( rc ) ); - return rc; - } - if ( board_info.magic != UNM_BDINFO_MAGIC ) { - DBGC ( phantom, "Phantom %p has bad board info magic %lx\n", - phantom, board_info.magic ); - DBGC_HD ( phantom, &board_info, sizeof ( board_info ) ); - return -EINVAL; - } - if ( board_info.header_version != UNM_BDINFO_VERSION ) { - DBGC ( phantom, "Phantom %p has bad board info version %lx\n", - phantom, board_info.header_version ); - DBGC_HD ( phantom, &board_info, sizeof ( board_info ) ); - return -EINVAL; - } - - /* Identify board type and number of ports */ - switch ( board_info.board_type ) { - case UNM_BRDTYPE_P3_4_GB: - case UNM_BRDTYPE_P3_4_GB_MM: - phantom->num_ports = 4; - break; - case UNM_BRDTYPE_P3_HMEZ: - case UNM_BRDTYPE_P3_IMEZ: - case UNM_BRDTYPE_P3_10G_CX4: - case UNM_BRDTYPE_P3_10G_CX4_LP: - case UNM_BRDTYPE_P3_10G_SFP_PLUS: - case UNM_BRDTYPE_P3_XG_LOM: - phantom->num_ports = 2; - break; - case UNM_BRDTYPE_P3_10000_BASE_T: - case UNM_BRDTYPE_P3_10G_XFP: - phantom->num_ports = 1; - break; - default: - DBGC ( phantom, "Phantom %p unrecognised board type %#lx; " - "assuming single-port\n", - phantom, board_info.board_type ); - phantom->num_ports = 1; - break; - } - DBGC ( phantom, "Phantom %p board type is %#lx (%d ports)\n", - phantom, board_info.board_type, phantom->num_ports ); - - return 0; +static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) { + uint32_t halt_status; + + halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS ); } /** @@ -1668,7 +1813,6 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) { static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { uint32_t cold_boot; uint32_t sw_reset; - physaddr_t dummy_dma_phys; unsigned int retries; uint32_t cmdpeg_state; uint32_t last_cmdpeg_state = 0; @@ -1681,6 +1825,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) { DBGC ( phantom, "Phantom %p command PEG already initialized\n", phantom ); + /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may + * have halted the PEGs to prevent internal bus + * collisions when the BIOS re-reads the expansion ROM. + */ + phantom_unhalt_pegs ( phantom ); return 0; } @@ -1707,10 +1856,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { UNM_CAM_RAM_WOL_PORT_MODE ); /* Pass dummy DMA area to card */ - dummy_dma_phys = virt_to_bus ( phantom->dma_buf->dummy_dma ); - DBGC ( phantom, "Phantom %p dummy DMA at %08lx\n", - phantom, dummy_dma_phys ); - phantom_write_hilo ( phantom, dummy_dma_phys, + phantom_write_hilo ( phantom, 0, UNM_NIC_REG_DUMMY_BUF_ADDR_LO, UNM_NIC_REG_DUMMY_BUF_ADDR_HI ); phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT, @@ -1750,12 +1896,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { /** * Read Phantom MAC address * - * @v phanton_port Phantom NIC port + * @v phanton_port Phantom NIC * @v ll_addr Buffer to fill with MAC address */ -static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, +static void phantom_get_macaddr ( struct phantom_nic *phantom, uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; union { uint8_t mac_addr[2][ETH_ALEN]; uint32_t dwords[3]; @@ -1765,7 +1910,7 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, /* Read the three dwords that include this MAC address and one other */ offset = ( UNM_CAM_RAM_MAC_ADDRS + - ( 12 * ( phantom_port->port / 2 ) ) ); + ( 12 * ( phantom->port / 2 ) ) ); for ( i = 0 ; i < 3 ; i++, offset += 4 ) { u.dwords[i] = phantom_readl ( phantom, offset ); } @@ -1773,10 +1918,36 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, /* Copy out the relevant MAC address */ for ( i = 0 ; i < ETH_ALEN ; i++ ) { ll_addr[ ETH_ALEN - i - 1 ] = - u.mac_addr[ phantom_port->port & 1 ][i]; + u.mac_addr[ phantom->port & 1 ][i]; } - DBGC ( phantom, "Phantom %p port %d MAC address is %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p MAC address is %s\n", + phantom, eth_ntoa ( ll_addr ) ); +} + +/** + * Check Phantom is enabled for boot + * + * @v phanton_port Phantom NIC + * @ret rc Return status code + * + * This is something of an ugly hack to accommodate an OEM + * requirement. The NIC has only one expansion ROM BAR, rather than + * one per port. To allow individual ports to be selectively + * enabled/disabled for PXE boot (as required), we must therefore + * leave the expansion ROM always enabled, and place the per-port + * enable/disable logic within the gPXE driver. + */ +static int phantom_check_boot_enable ( struct phantom_nic *phantom ) { + unsigned long boot_enable; + + boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE ); + if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) { + DBGC ( phantom, "Phantom %p PXE boot is disabled\n", + phantom ); + return -ENOTSUP; + } + + return 0; } /** @@ -1820,25 +1991,27 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) { */ static int phantom_probe ( struct pci_device *pci, const struct pci_device_id *id __unused ) { - struct phantom_nic *phantom; struct net_device *netdev; - struct phantom_nic_port *phantom_port; - int i; + struct phantom_nic *phantom; + struct settings *parent_settings; int rc; - /* Phantom NICs expose multiple PCI functions, used for - * virtualisation. Ignore everything except function 0. - */ - if ( PCI_FUNC ( pci->devfn ) != 0 ) - return -ENODEV; - /* Allocate Phantom device */ - phantom = zalloc ( sizeof ( *phantom ) ); - if ( ! phantom ) { + netdev = alloc_etherdev ( sizeof ( *phantom ) ); + if ( ! netdev ) { rc = -ENOMEM; - goto err_alloc_phantom; + goto err_alloc_etherdev; } - pci_set_drvdata ( pci, phantom ); + netdev_init ( netdev, &phantom_operations ); + phantom = netdev_priv ( netdev ); + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( phantom, 0, sizeof ( *phantom ) ); + phantom->port = PCI_FUNC ( pci->devfn ); + assert ( phantom->port < PHN_MAX_NUM_PORTS ); + settings_init ( &phantom->settings, + &phantom_settings_operations, + &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC ); /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -1847,87 +2020,66 @@ static int phantom_probe ( struct pci_device *pci, if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 ) goto err_map_crb; - /* Read flash information */ - if ( ( rc = phantom_read_flash ( phantom ) ) != 0 ) - goto err_read_flash; - - /* Allocate net devices for each port */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - netdev = alloc_etherdev ( sizeof ( *phantom_port ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err_alloc_etherdev; - } - phantom->netdev[i] = netdev; - netdev_init ( netdev, &phantom_operations ); - phantom_port = netdev_priv ( netdev ); - netdev->dev = &pci->dev; - phantom_port->phantom = phantom; - phantom_port->port = i; - } - /* BUG5945 - need to hack PCI config space on P3 B1 silicon. * B2 will have this fixed; remove this hack when B1 is no * longer in use. */ - for ( i = 0 ; i < 8 ; i++ ) { - uint32_t temp; - pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i ); - pci_read_config_dword ( pci, 0xc8, &temp ); - pci_read_config_dword ( pci, 0xc8, &temp ); - pci_write_config_dword ( pci, 0xc8, 0xf1000 ); + if ( PCI_FUNC ( pci->devfn ) == 0 ) { + unsigned int i; + for ( i = 0 ; i < 8 ; i++ ) { + uint32_t temp; + pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i ); + pci_read_config_dword ( pci, 0xc8, &temp ); + pci_read_config_dword ( pci, 0xc8, &temp ); + pci_write_config_dword ( pci, 0xc8, 0xf1000 ); + } + pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 ); } - pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 ); - /* Allocate dummy DMA buffer and perform initial hardware handshake */ - phantom->dma_buf = malloc_dma ( sizeof ( *(phantom->dma_buf) ), - UNM_DMA_BUFFER_ALIGN ); - if ( ! phantom->dma_buf ) - goto err_dma_buf; + /* Initialise the command PEG */ if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 ) goto err_init_cmdpeg; - /* Initialise the receive firmware */ + /* Initialise the receive PEG */ if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 ) goto err_init_rcvpeg; /* Read MAC addresses */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - phantom_port = netdev_priv ( phantom->netdev[i] ); - phantom_get_macaddr ( phantom_port, - phantom->netdev[i]->ll_addr ); - } + phantom_get_macaddr ( phantom, netdev->ll_addr ); + + /* Skip if boot disabled on NIC */ + if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 ) + goto err_check_boot_enable; /* Register network devices */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - if ( ( rc = register_netdev ( phantom->netdev[i] ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not register port " - "%d: %s\n", phantom, i, strerror ( rc ) ); - goto err_register_netdev; - } + if ( ( rc = register_netdev ( netdev ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not register net device: " + "%s\n", phantom, strerror ( rc ) ); + goto err_register_netdev; + } + + /* Register settings blocks */ + parent_settings = netdev_settings ( netdev ); + if ( ( rc = register_settings ( &phantom->settings, + parent_settings ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not register settings: " + "%s\n", phantom, strerror ( rc ) ); + goto err_register_settings; } return 0; - i = ( phantom->num_ports - 1 ); + unregister_settings ( &phantom->settings ); + err_register_settings: + unregister_netdev ( netdev ); err_register_netdev: - for ( ; i >= 0 ; i-- ) - unregister_netdev ( phantom->netdev[i] ); + err_check_boot_enable: err_init_rcvpeg: err_init_cmdpeg: - free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) ); - phantom->dma_buf = NULL; - err_dma_buf: - i = ( phantom->num_ports - 1 ); - err_alloc_etherdev: - for ( ; i >= 0 ; i-- ) { - netdev_nullify ( phantom->netdev[i] ); - netdev_put ( phantom->netdev[i] ); - } - err_read_flash: err_map_crb: - free ( phantom ); - err_alloc_phantom: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc_etherdev: return rc; } @@ -1937,18 +2089,13 @@ static int phantom_probe ( struct pci_device *pci, * @v pci PCI device */ static void phantom_remove ( struct pci_device *pci ) { - struct phantom_nic *phantom = pci_get_drvdata ( pci ); - int i; + struct net_device *netdev = pci_get_drvdata ( pci ); + struct phantom_nic *phantom = netdev_priv ( netdev ); - for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) - unregister_netdev ( phantom->netdev[i] ); - free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) ); - phantom->dma_buf = NULL; - for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) { - netdev_nullify ( phantom->netdev[i] ); - netdev_put ( phantom->netdev[i] ); - } - free ( phantom ); + unregister_settings ( &phantom->settings ); + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); } /** Phantom PCI IDs */ |