Re: [PATCH v3 net-next 1/2] net: ethernet: slicoss: add slicoss gigabit ethernet driver

From: Lino Sanfilippo
Date: Mon Nov 28 2016 - 15:47:08 EST


Hi Markus,

On 27.11.2016 18:59, Markus Böhme wrote:
> Hello Lino,
>
> just some things barely worth mentioning:
>

>
> I found a bunch of unused #defines in slic.h. I cannot judge if they are
> worth keeping:
>
> SLIC_VRHSTATB_LONGE
> SLIC_VRHSTATB_PREA
> SLIC_ISR_IO
> SLIC_ISR_PING_MASK
> SLIC_GIG_SPEED_MASK
> SLIC_GMCR_RESET
> SLIC_XCR_RESET
> SLIC_XCR_XMTEN
> SLIC_XCR_PAUSEEN
> SLIC_XCR_LOADRNG
> SLIC_REG_DBAR
> SLIC_REG_PING
> SLIC_REG_DUMP_CMD
> SLIC_REG_DUMP_DATA
> SLIC_REG_WRHOSTID
> SLIC_REG_LOW_POWER
> SLIC_REG_RESET_IFACE
> SLIC_REG_ADDR_UPPER
> SLIC_REG_HBAR64
> SLIC_REG_DBAR64
> SLIC_REG_CBAR64
> SLIC_REG_RBAR64
> SLIC_REG_WRVLANID
> SLIC_REG_READ_XF_INFO
> SLIC_REG_WRITE_XF_INFO
> SLIC_REG_TICKS_PER_SEC
>
> These device IDs are not used, either, but maybe it's good to keep them
> for documentation purposes:
>
> PCI_SUBDEVICE_ID_ALACRITECH_1000X1_2
> PCI_SUBDEVICE_ID_ALACRITECH_SES1001T
> PCI_SUBDEVICE_ID_ALACRITECH_SEN2002XT
> PCI_SUBDEVICE_ID_ALACRITECH_SEN2001XT
> PCI_SUBDEVICE_ID_ALACRITECH_SEN2104ET
> PCI_SUBDEVICE_ID_ALACRITECH_SEN2102ET
>

I left these defines in for both documentation and to avoid gaps in
register ranges. I would like to keep this as it is.

>> +
>> +/* SLIC EEPROM structure for Oasis */
>> +struct slic_mojave_eeprom {
>
> Comment: "for Mojave".

Will fix, thanks,

>
> [...]
>
>> +struct slic_device {
>> + struct pci_dev *pdev;
>> + struct net_device *netdev;
>> + void __iomem *regs;
>> + /* upper address setting lock */
>> + spinlock_t upper_lock;
>> + struct slic_shmem shmem;
>> + struct napi_struct napi;
>> + struct slic_rx_queue rxq;
>> + struct slic_tx_queue txq;
>> + struct slic_stat_queue stq;
>> + struct slic_stats stats;
>> + struct slic_upr_list upr_list;
>> + /* link configuration lock */
>> + spinlock_t link_lock;
>> + bool promisc;
>> + bool autoneg;
>> + int speed;
>> + int duplex;
>
> Maybe make speed and duplex unsigned? They are assigned and compared
> against unsigned values in slicoss.c, so this would get rid of some
> (benign, because of the range of the values) -Wsign-compare warnings in
> slic_configure_link_locked. However, in a comparison there SPEED_UNKNOWN
> would need to be casted to unsigned to prevent another one popping up.
>

There is indeed a bunch of warnings concerning signedness. Will have a look
at all of them. However I think I will keep "speed" as an int, because casting
SPEED_UNKNOWN to an unsigned int is IMHO an ugly thing to do.

> [...]
>
>> +#endif /* _SLIC_H */
>> diff --git a/drivers/net/ethernet/alacritech/slicoss.c b/drivers/net/ethernet/alacritech/slicoss.c
>> new file mode 100644
>> index 0000000..8cd862a
>> --- /dev/null
>> +++ b/drivers/net/ethernet/alacritech/slicoss.c
>> @@ -0,0 +1,1867 @@
>
> [...]
>
>> +
>> +static const struct pci_device_id slic_id_tbl[] = {
>> + { PCI_DEVICE(PCI_VENDOR_ID_ALACRITECH,
>> + PCI_DEVICE_ID_ALACRITECH_MOAVE) },
>
> I missed this in slic.h, but is this a typo and "MOAVE" should be
> "MOJAVE"? There are a couple similar #defines in slic.h.

This should definitely be "Mojave". Will fix it.

>
> [...]
>
>> +static void slic_refill_rx_queue(struct slic_device *sdev, gfp_t gfp)
>> +{
>> + const unsigned int ALIGN_MASK = SLIC_RX_BUFF_ALIGN - 1;
>> + unsigned int maplen = SLIC_RX_BUFF_SIZE;
>> + struct slic_rx_queue *rxq = &sdev->rxq;
>> + struct net_device *dev = sdev->netdev;
>> + struct slic_rx_buffer *buff;
>> + struct slic_rx_desc *desc;
>> + unsigned int misalign;
>> + unsigned int offset;
>> + struct sk_buff *skb;
>> + dma_addr_t paddr;
>> +
>> + while (slic_get_free_rx_descs(rxq) > SLIC_MAX_REQ_RX_DESCS) {
>> + skb = alloc_skb(maplen + ALIGN_MASK, gfp);
>> + if (!skb)
>> + break;
>> +
>> + paddr = dma_map_single(&sdev->pdev->dev, skb->data, maplen,
>> + DMA_FROM_DEVICE);
>> + if (dma_mapping_error(&sdev->pdev->dev, paddr)) {
>> + netdev_err(dev, "mapping rx packet failed\n");
>> + /* drop skb */
>> + dev_kfree_skb_any(skb);
>> + break;
>> + }
>> + /* ensure head buffer descriptors are 256 byte aligned */
>> + offset = 0;
>> + misalign = paddr & ALIGN_MASK;
>> + if (misalign) {
>> + offset = SLIC_RX_BUFF_ALIGN - misalign;
>> + skb_reserve(skb, offset);
>> + }
>> + /* the HW expects dma chunks for descriptor + frame data */
>> + desc = (struct slic_rx_desc *)skb->data;
>> + memset(desc, 0, sizeof(*desc));
>> +
>> + buff = &rxq->rxbuffs[rxq->put_idx];
>> + buff->skb = skb;
>> + dma_unmap_addr_set(buff, map_addr, paddr);
>> + dma_unmap_len_set(buff, map_len, maplen);
>> + buff->addr_offset = offset;
>> + /* head buffer descriptors are placed immediately before skb */
>> + slic_write(sdev, SLIC_REG_HBAR, lower_32_bits(paddr) +
>> + offset);
>
> This fits nicely on one line. :-)

Right, will fix.

>
> [...]
>
>> +static int slic_init_tx_queue(struct slic_device *sdev)
>> +{
>> + struct slic_tx_queue *txq = &sdev->txq;
>> + struct slic_tx_buffer *buff;
>> + struct slic_tx_desc *desc;
>> + int err;
>> + int i;
>
> You could make i unsigned...
>

>> +
>> + txq->len = SLIC_NUM_TX_DESCS;
>> + txq->put_idx = 0;
>> + txq->done_idx = 0;
>> +
>> + txq->txbuffs = kcalloc(txq->len, sizeof(*buff), GFP_KERNEL);
>> + if (!txq->txbuffs)
>> + return -ENOMEM;
>> +
>> + txq->dma_pool = dma_pool_create("slic_pool", &sdev->pdev->dev,
>> + sizeof(*desc), SLIC_TX_DESC_ALIGN,
>> + 4096);
>> + if (!txq->dma_pool) {
>> + err = -ENOMEM;
>> + netdev_err(sdev->netdev, "failed to create dma pool\n");
>> + goto free_buffs;
>> + }
>> +
>> + for (i = 0; i < txq->len; i++) {
>
> ...to fix a signed/unsigned comparison warning here, but...
>
>> + buff = &txq->txbuffs[i];
>> + desc = dma_pool_zalloc(txq->dma_pool, GFP_KERNEL,
>> + &buff->desc_paddr);
>> + if (!desc) {
>> + netdev_err(sdev->netdev,
>> + "failed to alloc pool chunk (%i)\n", i);
>> + err = -ENOMEM;
>> + goto free_descs;
>> + }
>> +
>> + desc->hnd = cpu_to_le32((u32)(i + 1));
>> + desc->cmd = SLIC_CMD_XMT_REQ;
>> + desc->flags = 0;
>> + desc->type = cpu_to_le32(SLIC_CMD_TYPE_DUMB);
>> + buff->desc = desc;
>> + }
>> +
>> + return 0;
>> +
>> +free_descs:
>> + while (i--) {
>
> ...this would require reworking this logic to prevent an endless loop,
> so probably not worth bothering, considering that txq->len is well
> within the positive signed range.

AFAICS the logic does not have to be changed. The while loop will also work
fine if "i" is unsigned.

>
>> + buff = &txq->txbuffs[i];
>> + dma_pool_free(txq->dma_pool, buff->desc, buff->desc_paddr);
>> + }
>> + dma_pool_destroy(txq->dma_pool);
>> +
>> +free_buffs:
>> + kfree(txq->txbuffs);
>> +
>> + return err;
>> +}
>> +
>> +static void slic_free_tx_queue(struct slic_device *sdev)
>> +{
>> + struct slic_tx_queue *txq = &sdev->txq;
>> + struct slic_tx_buffer *buff;
>> + int i;
>
> Make i unsigned? One warning less, almost no work invested.
>
>> +
>> + for (i = 0; i < txq->len; i++) {
>> + buff = &txq->txbuffs[i];
>> + dma_pool_free(txq->dma_pool, buff->desc, buff->desc_paddr);
>> + if (!buff->skb)
>> + continue;
>> +
>> + dma_unmap_single(&sdev->pdev->dev,
>> + dma_unmap_addr(buff, map_addr),
>> + dma_unmap_len(buff, map_len), DMA_TO_DEVICE);
>> + consume_skb(buff->skb);
>> + }
>> + dma_pool_destroy(txq->dma_pool);
>> +
>> + kfree(txq->txbuffs);
>> +}
>> +
>
> [...]
>
>> +static void slic_free_rx_queue(struct slic_device *sdev)
>> +{
>> + struct slic_rx_queue *rxq = &sdev->rxq;
>> + struct slic_rx_buffer *buff;
>> + int i;
>
> Unsigned?
>
>> +
>> + /* free rx buffers */
>> + for (i = 0; i < rxq->len; i++) {
>> + buff = &rxq->rxbuffs[i];
>> +
>> + if (!buff->skb)
>> + continue;
>> +
>> + dma_unmap_single(&sdev->pdev->dev,
>> + dma_unmap_addr(buff, map_addr),
>> + dma_unmap_len(buff, map_len),
>> + DMA_FROM_DEVICE);
>> + consume_skb(buff->skb);
>> + }
>> + kfree(rxq->rxbuffs);
>> +}
>
> [...]
>
>> +static int slic_load_firmware(struct slic_device *sdev)
>> +{
>> + u32 sectstart[SLIC_FIRMWARE_MAX_SECTIONS];
>> + u32 sectsize[SLIC_FIRMWARE_MAX_SECTIONS];
>> + const struct firmware *fw;
>> + unsigned int datalen;
>> + const char *file;
>> + int code_start;
>> + u32 numsects;
>> + int idx = 0;
>> + u32 sect;
>> + u32 instr;
>> + u32 addr;
>> + u32 base;
>> + int err;
>> + int i;
>
> Make i unsigned?
>
>> +
>> + file = (sdev->model == SLIC_MODEL_OASIS) ? SLIC_FIRMWARE_OASIS :
>> + SLIC_FIRMWARE_MOAVE;
>> + err = request_firmware(&fw, file, &sdev->pdev->dev);
>> + if (err) {
>> + dev_err(&sdev->pdev->dev, "failed to load firmware %s\n", file);
>> + return err;
>> + }
>> + /* Do an initial sanity check concerning firmware size now. A further
>> + * check follows below.
>> + */
>> + if (fw->size < SLIC_FIRMWARE_MIN_SIZE) {
>> + dev_err(&sdev->pdev->dev,
>> + "invalid firmware size %zu (min is %u)\n", fw->size,
>> + SLIC_FIRMWARE_MIN_SIZE);
>> + err = -EINVAL;
>> + goto release;
>> + }
>> +
>> + numsects = slic_read_dword_from_firmware(fw, &idx);
>> + if (numsects == 0 || numsects > SLIC_FIRMWARE_MAX_SECTIONS) {
>> + dev_err(&sdev->pdev->dev,
>> + "invalid number of sections in firmware: %u", numsects);
>> + err = -EINVAL;
>> + goto release;
>> + }
>> +
>> + datalen = numsects * 8 + 4;
>> + for (i = 0; i < numsects; i++) {
>> + sectsize[i] = slic_read_dword_from_firmware(fw, &idx);
>> + datalen += sectsize[i];
>> + }
>> +
>> + /* do another sanity check against firmware size */
>> + if (datalen > fw->size) {
>> + dev_err(&sdev->pdev->dev,
>> + "invalid firmware size %zu (expected >= %u)\n",
>> + fw->size, datalen);
>> + err = -EINVAL;
>> + goto release;
>> + }
>> + /* get sections */
>> + for (i = 0; i < numsects; i++)
>> + sectstart[i] = slic_read_dword_from_firmware(fw, &idx);
>> +
>> + code_start = idx;
>> + instr = slic_read_dword_from_firmware(fw, &idx);
>> +
>> + for (sect = 0; sect < numsects; sect++) {
>> + unsigned int ssize = sectsize[sect] >> 3;
>> +
>> + base = sectstart[sect];
>> +
>> + for (addr = 0; addr < ssize; addr++) {
>> + /* write out instruction address */
>> + slic_write(sdev, SLIC_REG_WCS, base + addr);
>> + /* write out instruction to low addr */
>> + slic_write(sdev, SLIC_REG_WCS, instr);
>> + instr = slic_read_dword_from_firmware(fw, &idx);
>> + /* write out instruction to high addr */
>> + slic_write(sdev, SLIC_REG_WCS, instr);
>> + instr = slic_read_dword_from_firmware(fw, &idx);
>> + }
>> + }
>> +
>> + idx = code_start;
>> +
>> + for (sect = 0; sect < numsects; sect++) {
>> + unsigned int ssize = sectsize[sect] >> 3;
>> +
>> + instr = slic_read_dword_from_firmware(fw, &idx);
>> + base = sectstart[sect];
>> + if (base < 0x8000)
>> + continue;
>> +
>> + for (addr = 0; addr < ssize; addr++) {
>> + /* write out instruction address */
>> + slic_write(sdev, SLIC_REG_WCS,
>> + SLIC_WCS_COMPARE | (base + addr));
>> + /* write out instruction to low addr */
>> + slic_write(sdev, SLIC_REG_WCS, instr);
>> + instr = slic_read_dword_from_firmware(fw, &idx);
>> + /* write out instruction to high addr */
>> + slic_write(sdev, SLIC_REG_WCS, instr);
>> + instr = slic_read_dword_from_firmware(fw, &idx);
>> + }
>> + }
>> + slic_flush_write(sdev);
>> + mdelay(10);
>> + /* everything OK, kick off the card */
>> + slic_write(sdev, SLIC_REG_WCS, SLIC_WCS_START);
>> + slic_flush_write(sdev);
>> + /* wait long enough for ucode to init card and reach the mainloop */
>> + mdelay(20);
>> +release:
>> + release_firmware(fw);
>> +
>> + return err;
>> +}
>
> [...]
>
>> +static int slic_init_iface(struct slic_device *sdev)
>> +{
>> + struct slic_shmem *sm = &sdev->shmem;
>> + int err;
>> +
>> + sdev->upr_list.pending = false;
>> +
>> + err = slic_init_shmem(sdev);
>> + if (err) {
>> + netdev_err(sdev->netdev, "failed to load firmware\n");
>
> Wrong error message.

Yep, will fix.

>
>> + return err;
>> + }
>
> [...]
>
>> +static netdev_tx_t slic_xmit(struct sk_buff *skb, struct net_device *dev)
>> +{
>> + struct slic_device *sdev = netdev_priv(dev);
>> + struct slic_tx_queue *txq = &sdev->txq;
>> + struct slic_tx_buffer *buff;
>> + struct slic_tx_desc *desc;
>> + dma_addr_t paddr;
>> + u32 cbar_val;
>> + u32 maplen;
>> +
>> + if (unlikely(slic_get_free_tx_descs(txq) < SLIC_MAX_REQ_TX_DESCS)) {
>> + netdev_err(dev, "BUG! not enought tx LEs left: %u\n",
>
> "Enough"?

Will fix.

>> + slic_get_free_tx_descs(txq));
>> + return NETDEV_TX_BUSY;
>> + }
>
> [...]
>
>> +static int slic_read_eeprom(struct slic_device *sdev)
>> +{
>> + unsigned int devfn = PCI_FUNC(sdev->pdev->devfn);
>> + struct slic_shmem *sm = &sdev->shmem;
>> + struct slic_shmem_data *sm_data = sm->shmem_data;
>> + const unsigned int MAX_LOOPS = 5000;
>
> Another benign -Wsign-compare warning can be fixed by either dropping
> the unsigned here or making i below unsigned, too.
>
>> + unsigned int codesize;
>> + unsigned char *eeprom;
>> + struct slic_upr *upr;
>> + dma_addr_t paddr;
>> + int err = 0;
>> + u8 *mac[2];
>> + int i = 0;
>> +
>> + eeprom = dma_zalloc_coherent(&sdev->pdev->dev, SLIC_EEPROM_SIZE,
>> + &paddr, GFP_KERNEL);
>> + if (!eeprom)
>> + return -ENOMEM;
>> +
>> + slic_write(sdev, SLIC_REG_ICR, SLIC_ICR_INT_OFF);
>> + /* setup ISP temporarily */
>> + slic_write(sdev, SLIC_REG_ISP, lower_32_bits(sm->isr_paddr));
>> +
>> + err = slic_new_upr(sdev, SLIC_UPR_CONFIG, paddr);
>> + if (!err) {
>> + for (i = 0; i < MAX_LOOPS; i++) {
>> + if (le32_to_cpu(sm_data->isr) & SLIC_ISR_UPC)
>> + break;
>> + mdelay(1);
>> + }
>> + if (i == MAX_LOOPS) {
>> + dev_err(&sdev->pdev->dev,
>> + "timed out while waiting for eeprom data\n");
>> + err = -ETIMEDOUT;
>> + }
>> + upr = slic_dequeue_upr(sdev);
>> + kfree(upr);
>> + }
>> +
>> + slic_write(sdev, SLIC_REG_ISP, 0);
>> + slic_write(sdev, SLIC_REG_ISR, 0);
>> + slic_flush_write(sdev);
>> +
>> + if (err)
>> + goto free_eeprom;
>> +
>> + if (sdev->model == SLIC_MODEL_OASIS) {
>> + struct slic_oasis_eeprom *oee;
>> +
>> + oee = (struct slic_oasis_eeprom *)eeprom;
>> + mac[0] = oee->mac;
>> + mac[1] = oee->mac2;
>> + codesize = le16_to_cpu(oee->eeprom_code_size);
>> + } else {
>> + struct slic_mojave_eeprom *mee;
>> +
>> + mee = (struct slic_mojave_eeprom *)eeprom;
>> + mac[0] = mee->mac;
>> + mac[1] = mee->mac2;
>> + codesize = le16_to_cpu(mee->eeprom_code_size);
>> + }
>> +
>> + if (!slic_eeprom_valid(eeprom, codesize)) {
>> + dev_err(&sdev->pdev->dev, "invalid checksum in eeprom\n");
>> + err = -EINVAL;
>> + goto free_eeprom;
>> + }
>> + /* set mac address */
>> + ether_addr_copy(sdev->netdev->dev_addr, mac[devfn]);
>> +free_eeprom:
>> + dma_free_coherent(&sdev->pdev->dev, SLIC_EEPROM_SIZE, eeprom, paddr);
>> +
>> + return err;
>> +}
>
> [...]
>
>> +static int slic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>> +{
>
> [...]
>
>> + err = register_netdev(dev);
>> + if (err) {
>> + dev_err(&pdev->dev, "failed to register net device: %i\n",
>> + err);
>
> Could be on one line.

Right, will adjust it.


> Regards,
> Markus
>

Thanks Markus!

Regards,
Lino