lkml.org 
[lkml]   [2022]   [Mar]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    SubjectRe: [PATCH 01/16] pata_parport: add core driver (PARIDE replacement)
    From
    Date
    Hello!

    On 3/5/22 11:13 PM, Ondrej Zary wrote:

    > Add pata_parport (PARIDE replacement) core libata driver.
    >
    > Signed-off-by: Ondrej Zary <linux@zary.sk>
    > ---
    > drivers/ata/Kconfig | 25 +
    > drivers/ata/Makefile | 2 +
    > drivers/ata/pata_parport/Kconfig | 10 +
    > drivers/ata/pata_parport/Makefile | 9 +
    > drivers/ata/pata_parport/pata_parport.c | 809 ++++++++++++++++++++++++
    > drivers/ata/pata_parport/pata_parport.h | 110 ++++

    I'd like to suggest to just name the new subdirectory 'parport'.
    And it looks like I'll need to update my MAINTAINBERS entry to include this driver... :-)

    [...]
    > diff --git a/drivers/ata/pata_parport/pata_parport.c b/drivers/ata/pata_parport/pata_parport.c
    > new file mode 100644
    > index 000000000000..7f814062cedd
    > --- /dev/null
    > +++ b/drivers/ata/pata_parport/pata_parport.c
    > @@ -0,0 +1,809 @@
    [...]
    > +static bool probe = 1;

    s/1/true/.

    [...]
    > +/* functions taken from libata-sff.c and converted from direct port I/O */
    > +static unsigned int pata_parport_devchk(struct ata_port *ap, unsigned int device)

    Should return bool now, see e.g..:

    https://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git/commit/?h=for-next&id=1336aa88d8553292604878c53538297fbc65bf0a

    > +{
    > + struct pi_adapter *pi = ap->host->private_data;
    > + u8 nsect, lbal;
    > +
    > + ap->ops->sff_dev_select(ap, device);

    Could call your sff-dev_select() methid directly here?

    [...]
    > +static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
    > + unsigned long deadline)
    > +{
    > + struct pi_adapter *pi = ap->host->private_data;
    > +
    > + pi_connect(pi);
    > + /* software reset. causes dev0 to be selected */
    > + pi->proto->write_regr(pi, 1, 6, ap->ctl);
    > + udelay(20); /* FIXME: flush */

    I don't think this FIXME applies to your driver...

    [...]
    > +static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,
    > + unsigned long deadline)
    > +{
    > + struct ata_port *ap = link->ap;
    > + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;

    Isn't this flag always set in your driver?

    > + unsigned int devmask = 0;
    > + int rc;
    > + u8 err;
    > +
    > + /* determine if device 0/1 are present */
    > + if (pata_parport_devchk(ap, 0))
    > + devmask |= (1 << 0);
    > + if (slave_possible && pata_parport_devchk(ap, 1))
    > + devmask |= (1 << 1);
    > +
    > + /* select device 0 again */
    > + ap->ops->sff_dev_select(ap, 0);

    Again, could you call this directly?

    > +
    > + /* issue bus reset */
    > + rc = pata_parport_bus_softreset(ap, devmask, deadline);
    > + /* if link is occupied, -ENODEV too is an error */
    > + if (rc && (rc != -ENODEV || sata_scr_valid(link))) {

    It's a PATA driver, why call sata_scr_valid() at all?

    [...]
    > +static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
    > +{
    > + struct pi_adapter *pi = ap->host->private_data;
    > + u8 tmp;
    > +
    > + pi_connect(pi);

    Why not call it after this *if*?

    > + if (device == 0)
    > + tmp = ATA_DEVICE_OBS;
    > + else
    > + tmp = ATA_DEVICE_OBS | ATA_DEV1;
    > +
    > + pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tmp);
    > + pi_disconnect_later(pi);
    > + ata_sff_pause(ap); /* needed; also flushes, for mmio */

    Does this comment make sense in your driver?

    [...]
    > +static void pata_parport_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
    > +{
    > + struct pi_adapter *pi = ap->host->private_data;
    > +
    > + pi_connect(pi);
    > + tf->command = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);

    Use tf->status please, see:

    https://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git/commit/?h=for-next&id=efcef265fd83d9a68a68926abecb3e1dd3e260a8

    > + tf->feature = pi->proto->read_regr(pi, 0, ATA_REG_ERR);

    Use tf->error as well please.

    [...]
    > +static void pata_parport_lost_interrupt(struct ata_port *ap)
    > +{
    > + u8 status;
    > + struct ata_queued_cmd *qc;
    > +
    > + /* Only one outstanding command per SFF channel */
    > + qc = ata_qc_from_tag(ap, ap->link.active_tag);
    > + /* We cannot lose an interrupt on a non-existent or polled command */
    > + if (!qc || qc->tf.flags & ATA_TFLAG_POLLING)
    > + return;
    > + /* See if the controller thinks it is still busy - if so the command
    > + isn't a lost IRQ but is still in progress */
    > + status = pata_parport_check_altstatus(ap);
    > + if (status & ATA_BUSY)
    > + return;
    > +
    > + /* There was a command running, we are no longer busy and we have
    > + no interrupt. */
    > + ata_port_warn(ap, "lost interrupt (Status 0x%x)\n", status);
    > + /* Run the host interrupt logic as if the interrupt had not been lost */
    > + ata_sff_port_intr(ap, qc);
    > +}

    Hm, it looks like ata_sff_lost_interrupt() could be used instead...

    > +
    > +static struct ata_port_operations pata_parport_port_ops = {

    Maybe inherit from ata_sff_port_ops?

    [...]
    > +static int default_test_proto(struct pi_adapter *pi, char *scratch)
    > +{
    > + int j, k;
    > + int e[2] = { 0, 0 };
    > +
    > + pi->proto->connect(pi);
    > +
    > + for (j = 0; j < 2; j++) {
    > + pi->proto->write_regr(pi, 0, 6, 0xa0 + j * 0x10);
    > + for (k = 0; k < 256; k++) {
    > + pi->proto->write_regr(pi, 0, 2, k ^ 0xaa);
    > + pi->proto->write_regr(pi, 0, 3, k ^ 0x55);
    > + if (pi->proto->read_regr(pi, 0, 2) != (k ^ 0xaa))
    > + e[j]++;
    > + }
    > + }
    > + pi->proto->disconnect(pi);
    > +
    > + if (verbose)
    > + dev_info(&pi->dev, "%s: port 0x%x, mode %d, test=(%d,%d)\n",

    Whyu 2 spaces after "mode"?

    > + pi->proto->name, pi->port,
    > + pi->mode, e[0], e[1]);
    > +
    > + return (e[0] && e[1]); /* not here if both > 0 */

    No need for parens.

    > +}

    This function kinda duplicates pata_parport_devchk()? :-)

    [...]
    > +static int pi_probe_mode(struct pi_adapter *pi, int max, char *scratch)
    > +{
    > + int best, range;
    > +
    > + if (pi->mode != -1) {
    > + if (pi->mode >= max)
    > + return 0;
    > + range = 3;
    > + if (pi->mode >= pi->proto->epp_first)
    > + range = 8;
    > + if ((range == 8) && (pi->port % 8))

    No need for inner parens...

    > + return 0;
    > + return (!pi_test_proto(pi, scratch));

    No need for outer parens, this time... :-)

    > + }
    > + best = -1;
    > + for (pi->mode = 0; pi->mode < max; pi->mode++) {
    > + range = 3;
    > + if (pi->mode >= pi->proto->epp_first)
    > + range = 8;
    > + if ((range == 8) && (pi->port % 8))

    No need for inner parens...

    > + break;
    > + if (!pi_test_proto(pi, scratch))
    > + best = pi->mode;
    > + }
    > + pi->mode = best;
    > + return (best > -1);

    No need for parens...

    > +}
    > +
    > +

    Isn't one empty line enough?

    > +static int pi_probe_unit(struct pi_adapter *pi, int unit, char *scratch)

    Looks like it's worth making this function return bool?

    [...]
    > +static ssize_t new_device_store(struct bus_type *bus, const char *buf, size_t count)
    > +{
    > + char port[12] = "auto";
    > + char protocol[8] = "auto";
    > + int mode = -1, unit = -1, delay = -1;
    > + struct pi_protocol *pr, *pr_wanted;
    > + struct device_driver *drv;
    > + struct parport *parport;
    > + int port_num, port_wanted, pr_num;
    > + bool ok = false;
    > +
    > + if (sscanf(buf, "%11s %7s %d %d %d",
    > + port, protocol, &mode, &unit, &delay) < 1)
    > + return -EINVAL;
    > +
    > + if (sscanf(port, "parport%u", &port_wanted) < 1) {
    > + if (!strcmp(port, "auto"))
    > + port_wanted = -1;
    > + else {

    Need {} on both branches.

    > + pr_err("invalid port name %s\n", port);
    > + return -EINVAL;
    > + }
    > + }
    > +
    > + drv = driver_find(protocol, &pata_parport_bus_type);
    > + if (!drv) {
    > + if (!strcmp(protocol, "auto"))
    > + pr_wanted = NULL;
    > + else {

    Same here.

    > + pr_err("protocol %s not found\n", protocol);
    > + return -EINVAL;
    > + }
    > + } else

    And here.

    > + pr_wanted = container_of(drv, struct pi_protocol, driver);
    [...]
    > +static ssize_t delete_device_store(struct bus_type *bus, const char *buf, size_t count)
    > +{
    > + struct device *dev;
    > + char device_name[32];
    > + int fields;
    > +
    > + fields = sscanf(buf, "%31s", device_name);
    > + if (fields < 1)

    Strange variable name where you expect only one field... And you don't even
    use it after this check, so hardly needed at all...

    [...]
    > diff --git a/drivers/ata/pata_parport/pata_parport.h b/drivers/ata/pata_parport/pata_parport.h
    > new file mode 100644
    > index 000000000000..c4201b809b20
    > --- /dev/null
    > +++ b/drivers/ata/pata_parport/pata_parport.h
    > @@ -0,0 +1,110 @@
    > +/* SPDX-License-Identifier: GPL-2.0-only */
    > +/*
    > + * paride.h (c) 1997-8 Grant R. Guenther <grant@torque.net>
    Doesn't match the file name anymore...

    > + * Under the terms of the GPL.
    > + *
    > + * This file defines the interface for adapter chip drivers.
    > + */
    > +
    > +#include <linux/libata.h>
    > +
    > +struct pi_adapter {
    > + struct device dev;
    > + struct pi_protocol *proto; /* adapter protocol */
    > + int port; /* base address of parallel port */
    > + int mode; /* transfer mode in use */
    > + int delay; /* adapter delay setting */
    > + int unit; /* unit number for chained adapters */
    > + int saved_r0; /* saved port state */
    > + int saved_r2; /* saved port state */
    > + unsigned long private; /* for protocol module */
    > + struct pardevice *pardev; /* pointer to pardevice */
    > + int claimed; /* parport has already been claimed */

    Use bool instead?

    > + struct timer_list timer; /* disconnect timer */
    > +};
    > +
    > +/* registers are addressed as (cont,regr)
    > + * cont: 0 for command register file, 1 for control register(s)
    > + * regr: 0-7 for register number.
    > + */
    > +
    > +/* macros and functions exported to the protocol modules */
    > +#define delay_p (pi->delay ? udelay(pi->delay) : (void)0)
    > +#define out_p(offs, byte) do { outb(byte, pi->port + offs); delay_p; } while (0)
    > +#define in_p(offs) (delay_p, inb(pi->port + offs))

    Hm, why not pass pi as an extra parameter?

    > +
    > +#define w0(byte) out_p(0, byte)
    > +#define r0() (in_p(0) & 0xff)

    Why mask the result of inb()?

    > +#define w1(byte) out_p(1, byte)
    > +#define r1() (in_p(1) & 0xff)
    > +#define w2(byte) out_p(2, byte)
    > +#define r2() (in_p(2) & 0xff)
    > +#define w3(byte) out_p(3, byte)
    > +#define w4(byte) out_p(4, byte)
    > +#define r4() (in_p(4) & 0xff)
    > +#define w4w(data) do { outw(data, pi->port + 4); delay_p; } while (0)
    > +#define w4l(data) do { outl(data, pi->port + 4); delay_p; } while (0)
    > +#define r4w() (delay_p, inw(pi->port + 4) & 0xffff)
    > +#define r4l() (delay_p, inl(pi->port + 4) & 0xffffffff)

    Again, why mask these?

    > +
    > +static inline u16 pi_swab16(char *b, int k)
    > +{
    > + union { u16 u; char t[2]; } r;
    > +
    > + r.t[0] = b[2 * k + 1]; r.t[1] = b[2 * k];
    > + return r.u;

    Hm, swab16() instead?

    > +}
    > +
    > +static inline u32 pi_swab32(char *b, int k)
    > +{
    > + union { u32 u; char f[4]; } r;
    > +
    > + r.f[0] = b[4 * k + 1]; r.f[1] = b[4 * k];
    > + r.f[2] = b[4 * k + 3]; r.f[3] = b[4 * k + 2];
    > + return r.u;

    And swab32() here instead?

    > +}
    [...]

    MNR, Sergey

    \
     
     \ /
      Last update: 2022-03-07 20:51    [W:2.993 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site