From e3b54cda6893726703a1fae66e9521bc231464cf Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 16:52:38 +0100 Subject: [PATCH 01/12] net: ks8851: Replace malloc()+memset() with calloc() Replace combination of malloc()+memset() with calloc() as the behavior is exactly the same and the amount of code is reduced. Moreover, remove printf() in the fail path, as it is useless, and return proper -ENOMEM return code. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 6643d1e9c1..51113a8981 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -604,12 +604,9 @@ int ks8851_mll_initialize(u8 dev_num, int base_addr) { struct eth_device *dev; - dev = malloc(sizeof(*dev)); - if (!dev) { - printf("Error: Failed to allocate memory\n"); - return -1; - } - memset(dev, 0, sizeof(*dev)); + dev = calloc(1, sizeof(*dev)); + if (!dev) + return -ENOMEM; dev->iobase = base_addr; From 8b41a167114ee847fb384f0d3ae61e86e89d133c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:02:21 +0100 Subject: [PATCH 02/12] net: ks8851: Remove RXQCR cache The cached RXQCR value is never updated, remove the cache and just use the bits in the cache directly in the code. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 51113a8981..03b8d7c9fd 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -51,7 +51,6 @@ union ks_tx_hdr { * @frame_cnt : number of frames received. * @bus_width : i/o bus width. * @irq : irq number assigned to this device. - * @rc_rxqcr : Cached copy of KS_RXQCR. * @rc_txcr : Cached copy of KS_TXCR. * @rc_ier : Cached copy of KS_IER. * @sharedbus : Multipex(addr and data bus) mode indicator. @@ -82,7 +81,6 @@ struct ks_net { u32 frame_cnt; int bus_width; int irq; - u16 rc_rxqcr; u16 rc_txcr; u16 rc_ier; u16 sharedbus; @@ -277,7 +275,7 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) /* 1. set sudo DMA mode */ ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); - ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* * 2. read prepend data @@ -295,7 +293,7 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) ks_inblk(dev, buf, ALIGN(len, 4)); /* 4. reset sudo DMA Mode */ - ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff); + ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL); } static void ks_rcv(struct eth_device *dev, uchar **pv_data) @@ -326,7 +324,7 @@ static void ks_rcv(struct eth_device *dev, uchar **pv_data) net_process_received_packet(*pv_data, frame_hdr->len); pv_data++; } else { - ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF)); + ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF); printf(DRIVERNAME ": bad packet\n"); } frame_hdr++; @@ -381,8 +379,7 @@ static void ks_setup(struct eth_device *dev) ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK); /* Setup RxQ Command Control (RXQCR) */ - ks->rc_rxqcr = RXQCR_CMD_CNTL; - ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr); + ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL); /* * set the force mode to half duplex, default is full duplex @@ -521,13 +518,13 @@ static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) /* 1. set sudo-DMA mode */ ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); - ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* 2. write status/lenth info */ ks_outblk(dev, ks->txh.txw, 4); /* 3. write pkt data */ ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); /* 4. reset sudo-DMA mode */ - ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff); + ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL); /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE); /* 6. wait until TXQCR_METFE is auto-cleared */ From 6a457313642525feacdfea973dbabd639f5b3261 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:02:51 +0100 Subject: [PATCH 03/12] net: ks8851: Use 16bit RXQCR access Per KS8851-16MLL, the RXQCR is a 16bit register. Use 16bit accessors to it consistently and drop the ks_wrreg8() function altogether, as it is not used anymore. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 03b8d7c9fd..c1c143dbaa 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -119,15 +119,6 @@ static u16 ks_rdreg16(struct eth_device *dev, u16 offset) return readw(dev->iobase); } -static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val) -{ - u8 shift_bit = (offset & 0x03); - u16 value_write = (u16)(val << ((offset & 1) << 3)); - - writew(offset | (BE0 << shift_bit), dev->iobase + 2); - writew(value_write, dev->iobase); -} - static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val) { writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); @@ -275,7 +266,7 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) /* 1. set sudo DMA mode */ ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); - ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); + ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* * 2. read prepend data @@ -293,7 +284,7 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) ks_inblk(dev, buf, ALIGN(len, 4)); /* 4. reset sudo DMA Mode */ - ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL); + ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL); } static void ks_rcv(struct eth_device *dev, uchar **pv_data) @@ -518,13 +509,13 @@ static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) /* 1. set sudo-DMA mode */ ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); - ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); + ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* 2. write status/lenth info */ ks_outblk(dev, ks->txh.txw, 4); /* 3. write pkt data */ ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); /* 4. reset sudo-DMA mode */ - ks_wrreg8(dev, KS_RXQCR, RXQCR_CMD_CNTL); + ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL); /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE); /* 6. wait until TXQCR_METFE is auto-cleared */ From b043597673855932bb824b3b4d73935ef47094bd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:18:55 +0100 Subject: [PATCH 04/12] net: ks8851: Trim down struct ks_net Most of the entries in the structure are useless, remove them. Inline the rest of uses where applicable. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 70 ++++++---------------------------------- 1 file changed, 9 insertions(+), 61 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index c1c143dbaa..17aa4fb886 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -27,44 +27,12 @@ static const struct chip_id chip_ids[] = { {0, NULL}, }; -/* - * union ks_tx_hdr - tx header data - * @txb: The header as bytes - * @txw: The header as 16bit, little-endian words - * - * A dual representation of the tx header data to allow - * access to individual bytes, and to allow 16bit accesses - * with 16bit alignment. - */ -union ks_tx_hdr { - u8 txb[4]; - __le16 txw[2]; -}; - /* * struct ks_net - KS8851 driver private data - * @net_device : The network device we're bound to - * @txh : temporaly buffer to save status/length. * @frame_head_info : frame header information for multi-pkt rx. - * @statelock : Lock on this structure for tx list. - * @msg_enable : The message flags controlling driver output (see ethtool). - * @frame_cnt : number of frames received. * @bus_width : i/o bus width. - * @irq : irq number assigned to this device. - * @rc_txcr : Cached copy of KS_TXCR. - * @rc_ier : Cached copy of KS_IER. * @sharedbus : Multipex(addr and data bus) mode indicator. - * @cmd_reg_cache : command register cached. - * @cmd_reg_cache_int : command register cached. Used in the irq handler. - * @promiscuous : promiscuous mode indicator. - * @all_mcast : mutlicast indicator. - * @mcast_lst_size : size of multicast list. - * @mcast_lst : multicast list. - * @mcast_bits : multicast enabed. - * @mac_addr : MAC address assigned to this device. - * @fid : frame id. * @extra_byte : number of extra byte prepended rx pkt. - * @enabled : indicator this device works. */ /* Receive multiplex framer header info */ @@ -74,27 +42,10 @@ struct type_frame_head { } fr_h_i[MAX_RECV_FRAMES]; struct ks_net { - struct net_device *netdev; - union ks_tx_hdr txh; struct type_frame_head *frame_head_info; - u32 msg_enable; - u32 frame_cnt; int bus_width; - int irq; - u16 rc_txcr; - u16 rc_ier; u16 sharedbus; - u16 cmd_reg_cache; - u16 cmd_reg_cache_int; - u16 promiscuous; - u16 all_mcast; - u16 mcast_lst_size; - u8 mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN]; - u8 mcast_bits[HW_MCAST_SIZE]; - u8 mac_addr[6]; - u8 fid; u8 extra_byte; - u8 enabled; } ks_str, *ks; #define BE3 0x8000 /* Byte Enable 3 */ @@ -156,7 +107,7 @@ static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len) static void ks_enable_int(struct eth_device *dev) { - ks_wrreg16(dev, KS_IER, ks->rc_ier); + ks_wrreg16(dev, KS_IER, IRQ_LCI | IRQ_TXI | IRQ_RXI); } static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode) @@ -290,12 +241,13 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) static void ks_rcv(struct eth_device *dev, uchar **pv_data) { struct type_frame_head *frame_hdr = ks->frame_head_info; + unsigned int frame_cnt; int i; - ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8; + frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8; /* read all header information */ - for (i = 0; i < ks->frame_cnt; i++) { + for (i = 0; i < frame_cnt; i++) { /* Checking Received packet status */ frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR); /* Get packet len from hardware */ @@ -304,7 +256,7 @@ static void ks_rcv(struct eth_device *dev, uchar **pv_data) } frame_hdr = ks->frame_head_info; - while (ks->frame_cnt--) { + while (frame_cnt--) { if ((frame_hdr->sts & RXFSHR_RXFV) && (frame_hdr->len < RX_BUF_SIZE) && frame_hdr->len) { @@ -394,13 +346,8 @@ static void ks_setup(struct eth_device *dev) static void ks_setup_int(struct eth_device *dev) { - ks->rc_ier = 0x00; - /* Clear the interrupts status of the hardware. */ ks_wrreg16(dev, KS_ISR, 0xffff); - - /* Enables the interrupts of the hardware. */ - ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI); } static int ks8851_mll_detect_chip(struct eth_device *dev) @@ -503,15 +450,16 @@ static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) { + __le16 txw[2]; /* start header at txb[0] to align txw entries */ - ks->txh.txw[0] = 0; - ks->txh.txw[1] = cpu_to_le16(len); + txw[0] = 0; + txw[1] = cpu_to_le16(len); /* 1. set sudo-DMA mode */ ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* 2. write status/lenth info */ - ks_outblk(dev, ks->txh.txw, 4); + ks_outblk(dev, txw, 4); /* 3. write pkt data */ ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); /* 4. reset sudo-DMA mode */ From 63f22f5998bc813ae5eacbf9210aa15cf80c0177 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:23:11 +0100 Subject: [PATCH 05/12] net: ks8851: Remove type_frame_head The packet status and length information should be extracted from the FIFO per-packet. Adjust the code such that it reads the packet meta data and then the packet afterward, if applicable. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 17aa4fb886..29bf40b2db 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -17,9 +17,6 @@ #define DRIVERNAME "ks8851_mll" -#define MAX_RECV_FRAMES 32 -#define MAX_BUF_SIZE 2048 -#define TX_BUF_SIZE 2000 #define RX_BUF_SIZE 2000 static const struct chip_id chip_ids[] = { @@ -29,20 +26,11 @@ static const struct chip_id chip_ids[] = { /* * struct ks_net - KS8851 driver private data - * @frame_head_info : frame header information for multi-pkt rx. * @bus_width : i/o bus width. * @sharedbus : Multipex(addr and data bus) mode indicator. - * @extra_byte : number of extra byte prepended rx pkt. + * @extra_byte : number of extra byte prepended rx pkt. */ - -/* Receive multiplex framer header info */ -struct type_frame_head { - u16 sts; /* Frame status */ - u16 len; /* Byte count */ -} fr_h_i[MAX_RECV_FRAMES]; - struct ks_net { - struct type_frame_head *frame_head_info; int bus_width; u16 sharedbus; u8 extra_byte; @@ -240,8 +228,8 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) static void ks_rcv(struct eth_device *dev, uchar **pv_data) { - struct type_frame_head *frame_hdr = ks->frame_head_info; unsigned int frame_cnt; + u16 sts, len; int i; frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8; @@ -249,28 +237,21 @@ static void ks_rcv(struct eth_device *dev, uchar **pv_data) /* read all header information */ for (i = 0; i < frame_cnt; i++) { /* Checking Received packet status */ - frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR); + sts = ks_rdreg16(dev, KS_RXFHSR); /* Get packet len from hardware */ - frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR); - frame_hdr++; - } + len = ks_rdreg16(dev, KS_RXFHBCR); - frame_hdr = ks->frame_head_info; - while (frame_cnt--) { - if ((frame_hdr->sts & RXFSHR_RXFV) && - (frame_hdr->len < RX_BUF_SIZE) && - frame_hdr->len) { + if ((sts & RXFSHR_RXFV) && len && (len < RX_BUF_SIZE)) { /* read data block including CRC 4 bytes */ - ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len); + ks_read_qmu(dev, (u16 *)(*pv_data), len); /* net_rx_packets buffer size is ok (*pv_data) */ - net_process_received_packet(*pv_data, frame_hdr->len); + net_process_received_packet(*pv_data, len); pv_data++; } else { ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF); printf(DRIVERNAME ": bad packet\n"); } - frame_hdr++; } } @@ -439,9 +420,6 @@ static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) /* Configure the PHY, initialize the link state */ ks8851_mll_phy_configure(dev); - /* static allocation of private informations */ - ks->frame_head_info = fr_h_i; - /* Turn on Tx + Rx */ ks8851_mll_enable(dev); From eb69d8bf3c043f126077e6b0905def8cca5c4723 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 18:15:46 +0100 Subject: [PATCH 06/12] net: ks8851: Clean up chip ID readout There is only one chip ID in the table of chip IDs for this chip. Read out the chip ID instead and mask off the last "revision" bit to check the chip ID, this works for all chips in the family. Then drop the chip ID passing around. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 29bf40b2db..3e89f894e5 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -19,11 +19,6 @@ #define RX_BUF_SIZE 2000 -static const struct chip_id chip_ids[] = { - {CIDER_ID, "KSZ8851"}, - {0, NULL}, -}; - /* * struct ks_net - KS8851 driver private data * @bus_width : i/o bus width. @@ -333,7 +328,7 @@ static void ks_setup_int(struct eth_device *dev) static int ks8851_mll_detect_chip(struct eth_device *dev) { - unsigned short val, i; + unsigned short val; ks_read_config(dev); @@ -350,19 +345,11 @@ static int ks8851_mll_detect_chip(struct eth_device *dev) debug("Read back KS8851 id 0x%x\n", val); - /* only one entry in the table */ - val &= 0xfff0; - for (i = 0; chip_ids[i].id != 0; i++) { - if (chip_ids[i].id == val) - break; - } - if (!chip_ids[i].id) { + if ((val & 0xfff0) != CIDER_ID) { printf(DRIVERNAME ": Unknown chip ID %04x\n", val); return -1; } - dev->priv = (void *)&chip_ids[i]; - return 0; } @@ -406,10 +393,6 @@ static void ks8851_mll_enable(struct eth_device *dev) static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) { - struct chip_id *id = dev->priv; - - debug(DRIVERNAME ": detected %s controller\n", id->name); - if (ks_read_selftest(dev)) { printf(DRIVERNAME ": Selftest failed\n"); return -1; From 8ec27b01bc8b492a3aacc76a299f4e24b1a44d0c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:25:29 +0100 Subject: [PATCH 07/12] net: ks8851: Checkpatch cleanup Fix various checkpatch complaints. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 3e89f894e5..060c4bd871 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -93,9 +93,9 @@ static void ks_enable_int(struct eth_device *dev) ks_wrreg16(dev, KS_IER, IRQ_LCI | IRQ_TXI | IRQ_RXI); } -static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode) +static void ks_set_powermode(struct eth_device *dev, unsigned int pwrmode) { - unsigned pmecr; + unsigned int pmecr; ks_rdreg16(dev, KS_GRR); pmecr = ks_rdreg16(dev, KS_PMECR); @@ -149,7 +149,7 @@ static void ks_read_config(struct eth_device *dev) * not currently specify the exact sequence, we have chosen something * that seems to work with our device. */ -static void ks_soft_reset(struct eth_device *dev, unsigned op) +static void ks_soft_reset(struct eth_device *dev, unsigned int op) { /* Disable interrupt first */ ks_wrreg16(dev, KS_IER, 0x0000); @@ -419,7 +419,7 @@ static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) /* 1. set sudo-DMA mode */ ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); - /* 2. write status/lenth info */ + /* 2. write status/length info */ ks_outblk(dev, txw, 4); /* 3. write pkt data */ ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); @@ -445,10 +445,10 @@ static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) if (retv >= tmplen + 12) { ks_write_qmu(dev, data, tmplen); return 0; - } else { - printf(DRIVERNAME ": failed to send packet: No buffer\n"); - return -1; } + + printf(DRIVERNAME ": failed to send packet: No buffer\n"); + return -1; } static void ks8851_mll_halt(struct eth_device *dev) @@ -470,11 +470,12 @@ static int ks8851_mll_recv(struct eth_device *dev) ks_wrreg16(dev, KS_ISR, status); - if ((status & IRQ_RXI)) + if (status & IRQ_RXI) ks_rcv(dev, (uchar **)net_rx_packets); - if ((status & IRQ_LDI)) { + if (status & IRQ_LDI) { u16 pmecr = ks_rdreg16(dev, KS_PMECR); + pmecr &= ~PMECR_WKEVT_MASK; ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK); } From b7c6ae2e82832b98572a538ddfe7c365c07f57d9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:35:00 +0100 Subject: [PATCH 08/12] net: ks8851: Pass around driver private data Introduce a private data structure for this driver with embedded struct eth_device and pass it around. This prepares the driver to work with both DM and non-DM systems. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 257 ++++++++++++++++++++------------------- 1 file changed, 133 insertions(+), 124 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 060c4bd871..1420ee9dbd 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -21,42 +21,46 @@ /* * struct ks_net - KS8851 driver private data + * @dev : legacy non-DM ethernet device structure + * @iobase : register base * @bus_width : i/o bus width. * @sharedbus : Multipex(addr and data bus) mode indicator. * @extra_byte : number of extra byte prepended rx pkt. */ struct ks_net { + struct eth_device dev; + phys_addr_t iobase; int bus_width; u16 sharedbus; u8 extra_byte; -} ks_str, *ks; +}; #define BE3 0x8000 /* Byte Enable 3 */ #define BE2 0x4000 /* Byte Enable 2 */ #define BE1 0x2000 /* Byte Enable 1 */ #define BE0 0x1000 /* Byte Enable 0 */ -static u8 ks_rdreg8(struct eth_device *dev, u16 offset) +static u8 ks_rdreg8(struct ks_net *ks, u16 offset) { u8 shift_bit = offset & 0x03; u8 shift_data = (offset & 1) << 3; - writew(offset | (BE0 << shift_bit), dev->iobase + 2); + writew(offset | (BE0 << shift_bit), ks->iobase + 2); - return (u8)(readw(dev->iobase) >> shift_data); + return (u8)(readw(ks->iobase) >> shift_data); } -static u16 ks_rdreg16(struct eth_device *dev, u16 offset) +static u16 ks_rdreg16(struct ks_net *ks, u16 offset) { - writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); + writew(offset | ((BE1 | BE0) << (offset & 0x02)), ks->iobase + 2); - return readw(dev->iobase); + return readw(ks->iobase); } -static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val) +static void ks_wrreg16(struct ks_net *ks, u16 offset, u16 val) { - writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); - writew(val, dev->iobase); + writew(offset | ((BE1 | BE0) << (offset & 0x02)), ks->iobase + 2); + writew(val, ks->iobase); } /* @@ -66,12 +70,12 @@ static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val) * @wptr: buffer address to save data * @len: length in byte to read */ -static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len) +static inline void ks_inblk(struct ks_net *ks, u16 *wptr, u32 len) { len >>= 1; while (len--) - *wptr++ = readw(dev->iobase); + *wptr++ = readw(ks->iobase); } /* @@ -80,42 +84,42 @@ static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len) * @wptr: buffer address * @len: length in byte to write */ -static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len) +static inline void ks_outblk(struct ks_net *ks, u16 *wptr, u32 len) { len >>= 1; while (len--) - writew(*wptr++, dev->iobase); + writew(*wptr++, ks->iobase); } -static void ks_enable_int(struct eth_device *dev) +static void ks_enable_int(struct ks_net *ks) { - ks_wrreg16(dev, KS_IER, IRQ_LCI | IRQ_TXI | IRQ_RXI); + ks_wrreg16(ks, KS_IER, IRQ_LCI | IRQ_TXI | IRQ_RXI); } -static void ks_set_powermode(struct eth_device *dev, unsigned int pwrmode) +static void ks_set_powermode(struct ks_net *ks, unsigned int pwrmode) { unsigned int pmecr; - ks_rdreg16(dev, KS_GRR); - pmecr = ks_rdreg16(dev, KS_PMECR); + ks_rdreg16(ks, KS_GRR); + pmecr = ks_rdreg16(ks, KS_PMECR); pmecr &= ~PMECR_PM_MASK; pmecr |= pwrmode; - ks_wrreg16(dev, KS_PMECR, pmecr); + ks_wrreg16(ks, KS_PMECR, pmecr); } /* * ks_read_config - read chip configuration of bus width. * @ks: The chip information */ -static void ks_read_config(struct eth_device *dev) +static void ks_read_config(struct ks_net *ks) { u16 reg_data = 0; /* Regardless of bus width, 8 bit read should always work. */ - reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF; - reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8; + reg_data = ks_rdreg8(ks, KS_CCR) & 0x00FF; + reg_data |= ks_rdreg8(ks, KS_CCR + 1) << 8; /* addr/data bus are multiplexed */ ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED; @@ -149,58 +153,58 @@ static void ks_read_config(struct eth_device *dev) * not currently specify the exact sequence, we have chosen something * that seems to work with our device. */ -static void ks_soft_reset(struct eth_device *dev, unsigned int op) +static void ks_soft_reset(struct ks_net *ks, unsigned int op) { /* Disable interrupt first */ - ks_wrreg16(dev, KS_IER, 0x0000); - ks_wrreg16(dev, KS_GRR, op); + ks_wrreg16(ks, KS_IER, 0x0000); + ks_wrreg16(ks, KS_GRR, op); mdelay(10); /* wait a short time to effect reset */ - ks_wrreg16(dev, KS_GRR, 0); + ks_wrreg16(ks, KS_GRR, 0); mdelay(1); /* wait for condition to clear */ } -void ks_enable_qmu(struct eth_device *dev) +void ks_enable_qmu(struct ks_net *ks) { u16 w; - w = ks_rdreg16(dev, KS_TXCR); + w = ks_rdreg16(ks, KS_TXCR); /* Enables QMU Transmit (TXCR). */ - ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE); + ks_wrreg16(ks, KS_TXCR, w | TXCR_TXE); /* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */ - w = ks_rdreg16(dev, KS_RXQCR); - ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE); + w = ks_rdreg16(ks, KS_RXQCR); + ks_wrreg16(ks, KS_RXQCR, w | RXQCR_RXFCTE); /* Enables QMU Receive (RXCR1). */ - w = ks_rdreg16(dev, KS_RXCR1); - ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE); + w = ks_rdreg16(ks, KS_RXCR1); + ks_wrreg16(ks, KS_RXCR1, w | RXCR1_RXE); } -static void ks_disable_qmu(struct eth_device *dev) +static void ks_disable_qmu(struct ks_net *ks) { u16 w; - w = ks_rdreg16(dev, KS_TXCR); + w = ks_rdreg16(ks, KS_TXCR); /* Disables QMU Transmit (TXCR). */ w &= ~TXCR_TXE; - ks_wrreg16(dev, KS_TXCR, w); + ks_wrreg16(ks, KS_TXCR, w); /* Disables QMU Receive (RXCR1). */ - w = ks_rdreg16(dev, KS_RXCR1); + w = ks_rdreg16(ks, KS_RXCR1); w &= ~RXCR1_RXE; - ks_wrreg16(dev, KS_RXCR1, w); + ks_wrreg16(ks, KS_RXCR1, w); } -static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) +static inline void ks_read_qmu(struct ks_net *ks, u16 *buf, u32 len) { u32 r = ks->extra_byte & 0x1; u32 w = ks->extra_byte - r; /* 1. set sudo DMA mode */ - ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); - ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); + ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI); + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* * 2. read prepend data @@ -210,41 +214,41 @@ static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) */ if (r) - ks_rdreg8(dev, 0); + ks_rdreg8(ks, 0); - ks_inblk(dev, buf, w + 2 + 2); + ks_inblk(ks, buf, w + 2 + 2); /* 3. read pkt data */ - ks_inblk(dev, buf, ALIGN(len, 4)); + ks_inblk(ks, buf, ALIGN(len, 4)); /* 4. reset sudo DMA Mode */ - ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL); + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL); } -static void ks_rcv(struct eth_device *dev, uchar **pv_data) +static void ks_rcv(struct ks_net *ks, uchar **pv_data) { unsigned int frame_cnt; u16 sts, len; int i; - frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8; + frame_cnt = ks_rdreg16(ks, KS_RXFCTR) >> 8; /* read all header information */ for (i = 0; i < frame_cnt; i++) { /* Checking Received packet status */ - sts = ks_rdreg16(dev, KS_RXFHSR); + sts = ks_rdreg16(ks, KS_RXFHSR); /* Get packet len from hardware */ - len = ks_rdreg16(dev, KS_RXFHBCR); + len = ks_rdreg16(ks, KS_RXFHBCR); if ((sts & RXFSHR_RXFV) && len && (len < RX_BUF_SIZE)) { /* read data block including CRC 4 bytes */ - ks_read_qmu(dev, (u16 *)(*pv_data), len); + ks_read_qmu(ks, (u16 *)(*pv_data), len); /* net_rx_packets buffer size is ok (*pv_data) */ net_process_received_packet(*pv_data, len); pv_data++; } else { - ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF); + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF); printf(DRIVERNAME ": bad packet\n"); } } @@ -256,13 +260,13 @@ static void ks_rcv(struct eth_device *dev, uchar **pv_data) * * Read and check the TX/RX memory selftest information. */ -static int ks_read_selftest(struct eth_device *dev) +static int ks_read_selftest(struct ks_net *ks) { u16 both_done = MBIR_TXMBF | MBIR_RXMBF; u16 mbir; int ret = 0; - mbir = ks_rdreg16(dev, KS_MBIR); + mbir = ks_rdreg16(ks, KS_MBIR); if ((mbir & both_done) != both_done) { printf(DRIVERNAME ": Memory selftest not finished\n"); @@ -284,55 +288,55 @@ static int ks_read_selftest(struct eth_device *dev) return ret; } -static void ks_setup(struct eth_device *dev) +static void ks_setup(struct ks_net *ks) { u16 w; /* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */ - ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); + ks_wrreg16(ks, KS_TXFDPR, TXFDPR_TXFPAI); /* Setup Receive Frame Data Pointer Auto-Increment */ - ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); + ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI); /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */ - ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK); + ks_wrreg16(ks, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK); /* Setup RxQ Command Control (RXQCR) */ - ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL); + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL); /* * set the force mode to half duplex, default is full duplex * because if the auto-negotiation fails, most switch uses * half-duplex. */ - w = ks_rdreg16(dev, KS_P1MBCR); + w = ks_rdreg16(ks, KS_P1MBCR); w &= ~P1MBCR_FORCE_FDX; - ks_wrreg16(dev, KS_P1MBCR, w); + ks_wrreg16(ks, KS_P1MBCR, w); w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP; - ks_wrreg16(dev, KS_TXCR, w); + ks_wrreg16(ks, KS_TXCR, w); w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC; /* Normal mode */ w |= RXCR1_RXPAFMA; - ks_wrreg16(dev, KS_RXCR1, w); + ks_wrreg16(ks, KS_RXCR1, w); } -static void ks_setup_int(struct eth_device *dev) +static void ks_setup_int(struct ks_net *ks) { /* Clear the interrupts status of the hardware. */ - ks_wrreg16(dev, KS_ISR, 0xffff); + ks_wrreg16(ks, KS_ISR, 0xffff); } -static int ks8851_mll_detect_chip(struct eth_device *dev) +static int ks8851_mll_detect_chip(struct ks_net *ks) { unsigned short val; - ks_read_config(dev); + ks_read_config(ks); - val = ks_rdreg16(dev, KS_CIDER); + val = ks_rdreg16(ks, KS_CIDER); if (val == 0xffff) { /* Special case -- no chip present */ @@ -353,63 +357,65 @@ static int ks8851_mll_detect_chip(struct eth_device *dev) return 0; } -static void ks8851_mll_reset(struct eth_device *dev) +static void ks8851_mll_reset(struct ks_net *ks) { /* wake up powermode to normal mode */ - ks_set_powermode(dev, PMECR_PM_NORMAL); + ks_set_powermode(ks, PMECR_PM_NORMAL); mdelay(1); /* wait for normal mode to take effect */ /* Disable interrupt and reset */ - ks_soft_reset(dev, GRR_GSR); + ks_soft_reset(ks, GRR_GSR); /* turn off the IRQs and ack any outstanding */ - ks_wrreg16(dev, KS_IER, 0x0000); - ks_wrreg16(dev, KS_ISR, 0xffff); + ks_wrreg16(ks, KS_IER, 0x0000); + ks_wrreg16(ks, KS_ISR, 0xffff); /* shutdown RX/TX QMU */ - ks_disable_qmu(dev); + ks_disable_qmu(ks); } -static void ks8851_mll_phy_configure(struct eth_device *dev) +static void ks8851_mll_phy_configure(struct ks_net *ks) { u16 data; - ks_setup(dev); - ks_setup_int(dev); + ks_setup(ks); + ks_setup_int(ks); /* Probing the phy */ - data = ks_rdreg16(dev, KS_OBCR); - ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA); + data = ks_rdreg16(ks, KS_OBCR); + ks_wrreg16(ks, KS_OBCR, data | OBCR_ODS_16MA); debug(DRIVERNAME ": phy initialized\n"); } -static void ks8851_mll_enable(struct eth_device *dev) +static void ks8851_mll_enable(struct ks_net *ks) { - ks_wrreg16(dev, KS_ISR, 0xffff); - ks_enable_int(dev); - ks_enable_qmu(dev); + ks_wrreg16(ks, KS_ISR, 0xffff); + ks_enable_int(ks); + ks_enable_qmu(ks); } static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) { - if (ks_read_selftest(dev)) { + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + if (ks_read_selftest(ks)) { printf(DRIVERNAME ": Selftest failed\n"); return -1; } - ks8851_mll_reset(dev); + ks8851_mll_reset(ks); /* Configure the PHY, initialize the link state */ - ks8851_mll_phy_configure(dev); + ks8851_mll_phy_configure(ks); /* Turn on Tx + Rx */ - ks8851_mll_enable(dev); + ks8851_mll_enable(ks); return 0; } -static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) +static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) { __le16 txw[2]; /* start header at txb[0] to align txw entries */ @@ -417,22 +423,23 @@ static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) txw[1] = cpu_to_le16(len); /* 1. set sudo-DMA mode */ - ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); - ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); + ks_wrreg16(ks, KS_TXFDPR, TXFDPR_TXFPAI); + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_SDA); /* 2. write status/length info */ - ks_outblk(dev, txw, 4); + ks_outblk(ks, txw, 4); /* 3. write pkt data */ - ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); + ks_outblk(ks, (u16 *)pdata, ALIGN(len, 4)); /* 4. reset sudo-DMA mode */ - ks_wrreg16(dev, KS_RXQCR, RXQCR_CMD_CNTL); + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL); /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ - ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE); + ks_wrreg16(ks, KS_TXQCR, TXQCR_METFE); /* 6. wait until TXQCR_METFE is auto-cleared */ - do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE); + do { } while (ks_rdreg16(ks, KS_TXQCR) & TXQCR_METFE); } static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) { + struct ks_net *ks = container_of(dev, struct ks_net, dev); u8 *data = (u8 *)packet; u16 tmplen = (u16)length; u16 retv; @@ -441,9 +448,9 @@ static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) * Extra space are required: * 4 byte for alignment, 4 for status/length, 4 for CRC */ - retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff; + retv = ks_rdreg16(ks, KS_TXMIR) & 0x1fff; if (retv >= tmplen + 12) { - ks_write_qmu(dev, data, tmplen); + ks_write_qmu(ks, data, tmplen); return 0; } @@ -453,7 +460,9 @@ static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) static void ks8851_mll_halt(struct eth_device *dev) { - ks8851_mll_reset(dev); + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + ks8851_mll_reset(ks); } /* @@ -464,20 +473,21 @@ static void ks8851_mll_halt(struct eth_device *dev) */ static int ks8851_mll_recv(struct eth_device *dev) { + struct ks_net *ks = container_of(dev, struct ks_net, dev); u16 status; - status = ks_rdreg16(dev, KS_ISR); + status = ks_rdreg16(ks, KS_ISR); - ks_wrreg16(dev, KS_ISR, status); + ks_wrreg16(ks, KS_ISR, status); if (status & IRQ_RXI) - ks_rcv(dev, (uchar **)net_rx_packets); + ks_rcv(ks, (uchar **)net_rx_packets); if (status & IRQ_LDI) { - u16 pmecr = ks_rdreg16(dev, KS_PMECR); + u16 pmecr = ks_rdreg16(ks, KS_PMECR); pmecr &= ~PMECR_WKEVT_MASK; - ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK); + ks_wrreg16(ks, KS_PMECR, pmecr | PMECR_WKEVT_LINK); } return 0; @@ -485,45 +495,44 @@ static int ks8851_mll_recv(struct eth_device *dev) static int ks8851_mll_write_hwaddr(struct eth_device *dev) { + struct ks_net *ks = container_of(dev, struct ks_net, dev); u16 addrl, addrm, addrh; - addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1]; - addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3]; - addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5]; + addrh = (ks->dev.enetaddr[0] << 8) | ks->dev.enetaddr[1]; + addrm = (ks->dev.enetaddr[2] << 8) | ks->dev.enetaddr[3]; + addrl = (ks->dev.enetaddr[4] << 8) | ks->dev.enetaddr[5]; - ks_wrreg16(dev, KS_MARH, addrh); - ks_wrreg16(dev, KS_MARM, addrm); - ks_wrreg16(dev, KS_MARL, addrl); + ks_wrreg16(ks, KS_MARH, addrh); + ks_wrreg16(ks, KS_MARM, addrm); + ks_wrreg16(ks, KS_MARL, addrl); return 0; } int ks8851_mll_initialize(u8 dev_num, int base_addr) { - struct eth_device *dev; + struct ks_net *ks; - dev = calloc(1, sizeof(*dev)); - if (!dev) + ks = calloc(1, sizeof(*ks)); + if (!ks) return -ENOMEM; - dev->iobase = base_addr; - - ks = &ks_str; + ks->iobase = base_addr; /* Try to detect chip. Will fail if not present. */ - if (ks8851_mll_detect_chip(dev)) { - free(dev); + if (ks8851_mll_detect_chip(ks)) { + free(ks); return -1; } - dev->init = ks8851_mll_init; - dev->halt = ks8851_mll_halt; - dev->send = ks8851_mll_send; - dev->recv = ks8851_mll_recv; - dev->write_hwaddr = ks8851_mll_write_hwaddr; - sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); + ks->dev.init = ks8851_mll_init; + ks->dev.halt = ks8851_mll_halt; + ks->dev.send = ks8851_mll_send; + ks->dev.recv = ks8851_mll_recv; + ks->dev.write_hwaddr = ks8851_mll_write_hwaddr; + sprintf(ks->dev.name, "%s-%hu", DRIVERNAME, dev_num); - eth_register(dev); + eth_register(&ks->dev); return 0; } From f725912624878faf7c552dd686425e0e14e75a8b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 17:54:45 +0100 Subject: [PATCH 09/12] net: ks8851: Split non-DM specific bits from common code Split network handling functions into non-DM specific parts and common code in preparation for conversion to DM. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 60 +++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 1420ee9dbd..2d41e5b9c7 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -395,10 +395,8 @@ static void ks8851_mll_enable(struct ks_net *ks) ks_enable_qmu(ks); } -static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) +static int ks8851_mll_init_common(struct ks_net *ks) { - struct ks_net *ks = container_of(dev, struct ks_net, dev); - if (ks_read_selftest(ks)) { printf(DRIVERNAME ": Selftest failed\n"); return -1; @@ -437,9 +435,8 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) do { } while (ks_rdreg16(ks, KS_TXQCR) & TXQCR_METFE); } -static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) +static int ks8851_mll_send_common(struct ks_net *ks, void *packet, int length) { - struct ks_net *ks = container_of(dev, struct ks_net, dev); u8 *data = (u8 *)packet; u16 tmplen = (u16)length; u16 retv; @@ -458,10 +455,8 @@ static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) return -1; } -static void ks8851_mll_halt(struct eth_device *dev) +static void ks8851_mll_halt_common(struct ks_net *ks) { - struct ks_net *ks = container_of(dev, struct ks_net, dev); - ks8851_mll_reset(ks); } @@ -471,9 +466,8 @@ static void ks8851_mll_halt(struct eth_device *dev) * needs to be enough to prevent a packet being discarded while * we are processing the previous one. */ -static int ks8851_mll_recv(struct eth_device *dev) +static int ks8851_mll_recv_common(struct ks_net *ks, uchar **data) { - struct ks_net *ks = container_of(dev, struct ks_net, dev); u16 status; status = ks_rdreg16(ks, KS_ISR); @@ -481,7 +475,7 @@ static int ks8851_mll_recv(struct eth_device *dev) ks_wrreg16(ks, KS_ISR, status); if (status & IRQ_RXI) - ks_rcv(ks, (uchar **)net_rx_packets); + ks_rcv(ks, data); if (status & IRQ_LDI) { u16 pmecr = ks_rdreg16(ks, KS_PMECR); @@ -493,18 +487,52 @@ static int ks8851_mll_recv(struct eth_device *dev) return 0; } -static int ks8851_mll_write_hwaddr(struct eth_device *dev) +static void ks8851_mll_write_hwaddr_common(struct ks_net *ks, u8 enetaddr[6]) { - struct ks_net *ks = container_of(dev, struct ks_net, dev); u16 addrl, addrm, addrh; - addrh = (ks->dev.enetaddr[0] << 8) | ks->dev.enetaddr[1]; - addrm = (ks->dev.enetaddr[2] << 8) | ks->dev.enetaddr[3]; - addrl = (ks->dev.enetaddr[4] << 8) | ks->dev.enetaddr[5]; + addrh = (enetaddr[0] << 8) | enetaddr[1]; + addrm = (enetaddr[2] << 8) | enetaddr[3]; + addrl = (enetaddr[4] << 8) | enetaddr[5]; ks_wrreg16(ks, KS_MARH, addrh); ks_wrreg16(ks, KS_MARM, addrm); ks_wrreg16(ks, KS_MARL, addrl); +} + +static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) +{ + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + return ks8851_mll_init_common(ks); +} + +static void ks8851_mll_halt(struct eth_device *dev) +{ + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + ks8851_mll_halt_common(ks); +} + +static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) +{ + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + return ks8851_mll_send_common(ks, packet, length); +} + +static int ks8851_mll_recv(struct eth_device *dev) +{ + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + return ks8851_mll_recv_common(ks, (uchar **)net_rx_packets); +} + +static int ks8851_mll_write_hwaddr(struct eth_device *dev) +{ + struct ks_net *ks = container_of(dev, struct ks_net, dev); + + ks8851_mll_write_hwaddr_common(ks, ks->dev.enetaddr); return 0; } From 9c9f3fc162ecbe1295ddf249e288a5a4739f5e07 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 18:47:10 +0100 Subject: [PATCH 10/12] net: ks8851: Receive one packet per recv call Instead of reading out the entire FIFO and possibly overwriting U-Boot memory, read out one packet per recv call, pass it to U-Boot network stack, and repeat. It is however necessary to cache RXFC value, because reading that one out clears it. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 57 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 2d41e5b9c7..2424e4297e 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -32,6 +32,7 @@ struct ks_net { phys_addr_t iobase; int bus_width; u16 sharedbus; + u16 rxfc; u8 extra_byte; }; @@ -225,33 +226,31 @@ static inline void ks_read_qmu(struct ks_net *ks, u16 *buf, u32 len) ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL); } -static void ks_rcv(struct ks_net *ks, uchar **pv_data) +static int ks_rcv(struct ks_net *ks, uchar *data) { - unsigned int frame_cnt; u16 sts, len; - int i; - frame_cnt = ks_rdreg16(ks, KS_RXFCTR) >> 8; + if (!ks->rxfc) + ks->rxfc = ks_rdreg16(ks, KS_RXFCTR) >> 8; - /* read all header information */ - for (i = 0; i < frame_cnt; i++) { - /* Checking Received packet status */ - sts = ks_rdreg16(ks, KS_RXFHSR); - /* Get packet len from hardware */ - len = ks_rdreg16(ks, KS_RXFHBCR); + if (!ks->rxfc) + return 0; - if ((sts & RXFSHR_RXFV) && len && (len < RX_BUF_SIZE)) { - /* read data block including CRC 4 bytes */ - ks_read_qmu(ks, (u16 *)(*pv_data), len); + /* Checking Received packet status */ + sts = ks_rdreg16(ks, KS_RXFHSR); + /* Get packet len from hardware */ + len = ks_rdreg16(ks, KS_RXFHBCR); - /* net_rx_packets buffer size is ok (*pv_data) */ - net_process_received_packet(*pv_data, len); - pv_data++; - } else { - ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF); - printf(DRIVERNAME ": bad packet\n"); - } + if ((sts & RXFSHR_RXFV) && len && (len < RX_BUF_SIZE)) { + /* read data block including CRC 4 bytes */ + ks_read_qmu(ks, (u16 *)data, len); + ks->rxfc--; + return len - 4; } + + ks_wrreg16(ks, KS_RXQCR, RXQCR_CMD_CNTL | RXQCR_RRXEF); + printf(DRIVERNAME ": bad packet\n"); + return 0; } /* @@ -407,6 +406,8 @@ static int ks8851_mll_init_common(struct ks_net *ks) /* Configure the PHY, initialize the link state */ ks8851_mll_phy_configure(ks); + ks->rxfc = 0; + /* Turn on Tx + Rx */ ks8851_mll_enable(ks); @@ -466,16 +467,17 @@ static void ks8851_mll_halt_common(struct ks_net *ks) * needs to be enough to prevent a packet being discarded while * we are processing the previous one. */ -static int ks8851_mll_recv_common(struct ks_net *ks, uchar **data) +static int ks8851_mll_recv_common(struct ks_net *ks, uchar *data) { u16 status; + int ret = 0; status = ks_rdreg16(ks, KS_ISR); ks_wrreg16(ks, KS_ISR, status); - if (status & IRQ_RXI) - ks_rcv(ks, data); + if (ks->rxfc || (status & IRQ_RXI)) + ret = ks_rcv(ks, data); if (status & IRQ_LDI) { u16 pmecr = ks_rdreg16(ks, KS_PMECR); @@ -484,7 +486,7 @@ static int ks8851_mll_recv_common(struct ks_net *ks, uchar **data) ks_wrreg16(ks, KS_PMECR, pmecr | PMECR_WKEVT_LINK); } - return 0; + return ret; } static void ks8851_mll_write_hwaddr_common(struct ks_net *ks, u8 enetaddr[6]) @@ -524,8 +526,13 @@ static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) static int ks8851_mll_recv(struct eth_device *dev) { struct ks_net *ks = container_of(dev, struct ks_net, dev); + int ret; - return ks8851_mll_recv_common(ks, (uchar **)net_rx_packets); + ret = ks8851_mll_recv_common(ks, net_rx_packets[0]); + if (ret) + net_process_received_packet(net_rx_packets[0], ret); + + return ret; } static int ks8851_mll_write_hwaddr(struct eth_device *dev) From 1d476de7c8fbb93aab95dd5b522488ca4bfdc5a0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 18:00:35 +0100 Subject: [PATCH 11/12] net: ks8851: Add DM support Add support for U-Boot DM and DT probing. Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- drivers/net/ks8851_mll.c | 103 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 2424e4297e..3ff173ad33 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -28,7 +28,9 @@ * @extra_byte : number of extra byte prepended rx pkt. */ struct ks_net { +#ifndef CONFIG_DM_ETH struct eth_device dev; +#endif phys_addr_t iobase; int bus_width; u16 sharedbus; @@ -502,6 +504,7 @@ static void ks8851_mll_write_hwaddr_common(struct ks_net *ks, u8 enetaddr[6]) ks_wrreg16(ks, KS_MARL, addrl); } +#ifndef CONFIG_DM_ETH static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) { struct ks_net *ks = container_of(dev, struct ks_net, dev); @@ -571,3 +574,103 @@ int ks8851_mll_initialize(u8 dev_num, int base_addr) return 0; } +#else /* ifdef CONFIG_DM_ETH */ +static int ks8851_start(struct udevice *dev) +{ + struct ks_net *ks = dev_get_priv(dev); + + return ks8851_mll_init_common(ks); +} + +static void ks8851_stop(struct udevice *dev) +{ + struct ks_net *ks = dev_get_priv(dev); + + ks8851_mll_halt_common(ks); +} + +static int ks8851_send(struct udevice *dev, void *packet, int length) +{ + struct ks_net *ks = dev_get_priv(dev); + int ret; + + ret = ks8851_mll_send_common(ks, packet, length); + + return ret ? 0 : -ETIMEDOUT; +} + +static int ks8851_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct ks_net *ks = dev_get_priv(dev); + uchar *data = net_rx_packets[0]; + int ret; + + ret = ks8851_mll_recv_common(ks, data); + if (ret) + *packetp = (void *)data; + + return ret ? ret : -EAGAIN; +} + +static int ks8851_write_hwaddr(struct udevice *dev) +{ + struct ks_net *ks = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + ks8851_mll_write_hwaddr_common(ks, pdata->enetaddr); + + return 0; +} + +static int ks8851_bind(struct udevice *dev) +{ + return device_set_name(dev, dev->name); +} + +static int ks8851_probe(struct udevice *dev) +{ + struct ks_net *ks = dev_get_priv(dev); + + /* Try to detect chip. Will fail if not present. */ + ks8851_mll_detect_chip(ks); + + return 0; +} + +static int ks8851_ofdata_to_platdata(struct udevice *dev) +{ + struct ks_net *ks = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = devfdt_get_addr(dev); + ks->iobase = pdata->iobase; + + return 0; +} + +static const struct eth_ops ks8851_ops = { + .start = ks8851_start, + .stop = ks8851_stop, + .send = ks8851_send, + .recv = ks8851_recv, + .write_hwaddr = ks8851_write_hwaddr, +}; + +static const struct udevice_id ks8851_ids[] = { + { .compatible = "micrel,ks8851-mll" }, + { } +}; + +U_BOOT_DRIVER(ks8851) = { + .name = "eth_ks8851", + .id = UCLASS_ETH, + .of_match = ks8851_ids, + .bind = ks8851_bind, + .ofdata_to_platdata = ks8851_ofdata_to_platdata, + .probe = ks8851_probe, + .ops = &ks8851_ops, + .priv_auto_alloc_size = sizeof(struct ks_net), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif From df4c4834fc008315bce2f978220ecc9da2e3862c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 25 Mar 2020 19:08:59 +0100 Subject: [PATCH 12/12] net: ks8851: Add Kconfig entries Convert CONFIG_KS8851_MLL and CONFIG_KS8851_MLL_BASEADDR to Kconfig Signed-off-by: Marek Vasut Cc: Eugen Hristev Cc: Joe Hershberger --- configs/at91sam9n12ek_mmc_defconfig | 2 ++ configs/at91sam9n12ek_nandflash_defconfig | 2 ++ configs/at91sam9n12ek_spiflash_defconfig | 2 ++ drivers/net/Kconfig | 14 ++++++++++++++ include/configs/at91sam9n12ek.h | 3 --- scripts/config_whitelist.txt | 2 -- 6 files changed, 20 insertions(+), 5 deletions(-) diff --git a/configs/at91sam9n12ek_mmc_defconfig b/configs/at91sam9n12ek_mmc_defconfig index 075daa79d3..308f097b60 100644 --- a/configs/at91sam9n12ek_mmc_defconfig +++ b/configs/at91sam9n12ek_mmc_defconfig @@ -47,6 +47,8 @@ CONFIG_NAND_ATMEL=y CONFIG_DM_SPI_FLASH=y CONFIG_SF_DEFAULT_SPEED=30000000 CONFIG_SPI_FLASH_ATMEL=y +CONFIG_KS8851_MLL=y +CONFIG_KS8851_MLL_BASEADDR=0x30000000 CONFIG_PINCTRL=y CONFIG_PINCTRL_AT91=y CONFIG_DM_SERIAL=y diff --git a/configs/at91sam9n12ek_nandflash_defconfig b/configs/at91sam9n12ek_nandflash_defconfig index b02be84493..fd6d13db9b 100644 --- a/configs/at91sam9n12ek_nandflash_defconfig +++ b/configs/at91sam9n12ek_nandflash_defconfig @@ -48,6 +48,8 @@ CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y CONFIG_DM_SPI_FLASH=y CONFIG_SF_DEFAULT_SPEED=30000000 CONFIG_SPI_FLASH_ATMEL=y +CONFIG_KS8851_MLL=y +CONFIG_KS8851_MLL_BASEADDR=0x30000000 CONFIG_PINCTRL=y CONFIG_PINCTRL_AT91=y CONFIG_DM_SERIAL=y diff --git a/configs/at91sam9n12ek_spiflash_defconfig b/configs/at91sam9n12ek_spiflash_defconfig index be8ef51a2d..97e29bdc6e 100644 --- a/configs/at91sam9n12ek_spiflash_defconfig +++ b/configs/at91sam9n12ek_spiflash_defconfig @@ -49,6 +49,8 @@ CONFIG_NAND_ATMEL=y CONFIG_DM_SPI_FLASH=y CONFIG_SF_DEFAULT_SPEED=30000000 CONFIG_SPI_FLASH_ATMEL=y +CONFIG_KS8851_MLL=y +CONFIG_KS8851_MLL_BASEADDR=0x30000000 CONFIG_PINCTRL=y CONFIG_PINCTRL_AT91=y CONFIG_DM_SERIAL=y diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f7855c92d3..0b08de0ef4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -307,6 +307,20 @@ config FSLDMAFEC This driver supports the network interface units in the ColdFire family. +config KS8851_MLL + bool "Microchip KS8851-MLL controller driver" + help + The Microchip KS8851 parallel bus external ethernet interface chip. + +if KS8851_MLL +if !DM_ETH +config KS8851_MLL_BASEADDR + hex "Microchip KS8851-MLL Base Address" + help + Define this to hold the physical address of the device (I/O space) +endif #DM_ETH +endif #KS8851_MLL + config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on ARCH_KIRKWOOD || ARCH_ORION5X diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h index 7ee569521e..706217fef9 100644 --- a/include/configs/at91sam9n12ek.h +++ b/include/configs/at91sam9n12ek.h @@ -63,9 +63,6 @@ "bootargs_mmc=root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait\0" /* Ethernet */ -#define CONFIG_KS8851_MLL -#define CONFIG_KS8851_MLL_BASEADDR 0x30000000 /* use NCS2 */ - #define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */ /* USB host */ diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 3f5e6504e1..9b6b45116a 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -942,8 +942,6 @@ CONFIG_KONA CONFIG_KONA_GPIO CONFIG_KONA_RESET_S CONFIG_KPROBES -CONFIG_KS8851_MLL -CONFIG_KS8851_MLL_BASEADDR CONFIG_KSNAV_NETCP_PDMA_CTRL_BASE CONFIG_KSNAV_NETCP_PDMA_RX_BASE CONFIG_KSNAV_NETCP_PDMA_RX_CH_NUM